migrate node fs paths to pathlib primary and reorg ctors/from_parent#8037
migrate node fs paths to pathlib primary and reorg ctors/from_parent#8037RonnyPfannschmidt wants to merge 5 commits intopytest-dev:mainfrom
Conversation
|
while fixing the typing issues it seems i introduced a bug in collection i keep missing atm im under the impression that resolving it will require a new type of node construction for sessions in order to avoid certain issues |
|
the failure in the plugins testing is due to a unavoidable issue with pytest-flakes, i'll check out whether it an be coordinated away |
asottile
left a comment
There was a problem hiding this comment.
hmm yeah the break is unfortunate, I wonder if there's some trick we could do with taking both fspath / fs_path parameters for some time and then deprecate / adjust? might make for a smoother transition for plugins (though of course, way more work for us!)
most of my comments are little type things, overall seems good 👍
7de346a to
c75ee78
Compare
nicoddemus
left a comment
There was a problem hiding this comment.
Overall is looking good! Left a few comments. 👍
src/_pytest/nodes.py
Outdated
|
|
||
| #: Filesystem path where this node was collected from (can be None). | ||
| self.fspath = fspath or getattr(parent, "fspath", None) | ||
| self.fs_path = fs_path |
There was a problem hiding this comment.
Being a bit nitpicky, but fs_path and fspath are too close to one another, I fear users will get the two confused all the time.
How about: path for the Path version? After all the fs prefix is a bit redudant.
There was a problem hiding this comment.
I agree with @nicoddemus, the name fs_path is not very pretty.
One thing against just path is that someday we'll also want to migrate our hooks to Path and their the py.path param is always path so the Path param would need a different name. And path is not very distinguishable either. But I can't think of something else.
There was a problem hiding this comment.
How about file_path? This is always a file right?
There was a problem hiding this comment.
there are situations where it ought to be a folder
- external collection utilities
- collection roots (a concept i intend to introduce as extension of the testpaths configuration (i think it needs a ticket)
- Packages ought to use it as well
| self.fspath = fspath | ||
|
|
||
| session = session or parent.session | ||
| name = str(rel) |
There was a problem hiding this comment.
This will end up with a name containing \ on Windows because we are no longer doing name = name.replace(os.sep, SEP). Is that intentional?
Also str seems redudant:
>>> local("src/pytest").relto(local("."))
'src\\pytest'There was a problem hiding this comment.
relto is from py.path.local - relative pathlib paths are relative
There was a problem hiding this comment.
Ahh I see, thanks, but does the comment about name.replace still apply?
>>> local("src/pytest").relto(local("."))
'src\\pytest'There was a problem hiding this comment.
Ahh OK so this needs fixing then. 👍
| nodeid = self.fspath.relto(session.config.rootdir) | ||
| assert parent is not None | ||
| session = parent.session | ||
| relp = session._bestrelpathcache[known_path] |
| assert parent is not None | ||
| session = parent.session | ||
| relp = session._bestrelpathcache[known_path] | ||
| if not relp.startswith(".." + os.sep): |
There was a problem hiding this comment.
Can we have a comment here explaining the purpose of this?
bluetech
left a comment
There was a problem hiding this comment.
Not a full review, just some comment.
src/_pytest/main.py
Outdated
| def __init__(self, config: Config) -> None: | ||
| super().__init__( | ||
| config.rootdir, parent=None, config=config, session=self, nodeid="" | ||
| fs_path=Path(config.rootdir), |
There was a problem hiding this comment.
| fs_path=Path(config.rootdir), | |
| fs_path=config.rootpath, |
src/_pytest/main.py
Outdated
| key = (type(x), x.fspath) | ||
| if key in node_cache2: | ||
| yield node_cache2[key] | ||
| keya = (type(x), x.fspath) |
There was a problem hiding this comment.
I suggest key2 to match node_cache2.
src/_pytest/main.py
Outdated
| key = (type(node), node.nodeid) | ||
| if key in matchnodes_cache: | ||
| rep = matchnodes_cache[key] | ||
| keyb = (type(node), str(node.nodeid)) |
There was a problem hiding this comment.
Here I would call it key_matchnodes.
Why is the str(node.nodeid) needed? Isn't nodeid already an str?
src/_pytest/nodes.py
Outdated
|
|
||
| #: Filesystem path where this node was collected from (can be None). | ||
| self.fspath = fspath or getattr(parent, "fspath", None) | ||
| self.fs_path = fs_path |
There was a problem hiding this comment.
I agree with @nicoddemus, the name fs_path is not very pretty.
One thing against just path is that someday we'll also want to migrate our hooks to Path and their the py.path param is always path so the Path param would need a different name. And path is not very distinguishable either. But I can't think of something else.
also helps to implement pytest-dev/pytest#8037
|
as soon as the pytest-flakes maintainer fins some time to merge/release the pipeline should get green, this still is a breaking change in terms of requiring people to actually write proper ctors im thinking of reintroducing implying for a little while and using the pytest-flakes pr as a example for propper ctors |
|
Cool thanks for the follow up
Not sure I follow can you please clarify that? |
|
Aka having the node ctors imply things and warning about it so plugins can migrate |
|
Ahh got it, thanks! |
|
@nicoddemus @bluetech it seems like the fragile base class issue is hitting this pr and many plugins way harder than what id hope for im not sure whether we should fix plugisn or reiterate the approach |
47833e9 to
57b1f33
Compare
What you mean exactly, in terms of the number of arguments that can be passed?
This might be the best way to go, as at least plugins will continue to work, and we can issue a warning for a few releases suggesting the change. With 7.0 we can then make the final breaking change. |
2fe61c1 to
0ee0897
Compare
|
@nicoddemus hitting another case of rebase demonstrating why primarily acceptance tests is a massive problem, will debug sometime later |
576997a to
6934346
Compare
6934346 to
de835f2
Compare
Co-authored-by: Ran Benita <ran@unusedvar.com>
de835f2 to
424f826
Compare
Co-authored-by: Bruno Oliveira <nicoddemus@gmail.com>
for more information, see https://pre-commit.ci
bluetech
left a comment
There was a problem hiding this comment.
I think it would be easier to evaluate this PR if it were split into at least two parts:
- The implied-arguments deprecation
- The pathlib conversions
Because they seem not really related, and it will be easier to review each one of these separately. But if it's too much work that's OK.
Regarding the implied-arguments deprecation - the code looks good to me but at a higher level I'm still not quite sure what is the reason for the deprecation, or of from_parent in general?
Regarding the pathlib conversion, that's great, I think it's the last major piece 👍 But the code is a little hard to review, having a PR which just does this part would really help me at least. Also regarding the name, I prefer path over fs_path, it's quite minor but I don't like how fs_path looks (in the hookspecs we stuck with path and fspath).
| "__dict__", | ||
| ) | ||
|
|
||
| name: str |
There was a problem hiding this comment.
Is mypy not able to figure these out on its own?
| fspath: Optional[py.path.local] = kw.pop("fspath", None) | ||
|
|
||
| if fspath is not None: | ||
| assert fs_path is None |
There was a problem hiding this comment.
| assert fs_path is None | |
| assert fs_path is None, "Specify either fspath or fs_path, not both" |
| @@ -0,0 +1 @@ | |||
| Deprecate implying node ctor arguments. | |||
There was a problem hiding this comment.
I think if I read this sentence as a user I would not be able to grok what it's about, so some more details would be good here, like what exactly is deprecated, and how to fix.
Also we usually add a corresponding note in the docs/deprecations.rst file (can just be a copy/paste of the changelog entry mostly).
| "implying {type.__name__}.{arg} from parent.{arg} has been deprecated\n" | ||
| "please use the Node.from_parent to have them be implied by the superclass named ctors", |
There was a problem hiding this comment.
| "implying {type.__name__}.{arg} from parent.{arg} has been deprecated\n" | |
| "please use the Node.from_parent to have them be implied by the superclass named ctors", | |
| "Implying {type.__name__}.{arg} from parent.{arg} has been deprecated.\n" | |
| "Please use Node.from_parent to have them be implied by the superclass named constructors.", |
| config: Optional[Config] = None, | ||
| session: Optional["Session"] = None, | ||
| nodeid: Optional[str] = None, | ||
| parent: Node, |
There was a problem hiding this comment.
this one i missed while restoring ctor based implication
| @@ -0,0 +1 @@ | |||
| Introduce ``Node.fs_path`` as pathlib replacement for ``Node.fspath`` | |||
There was a problem hiding this comment.
| Introduce ``Node.fs_path`` as pathlib replacement for ``Node.fspath`` | |
| Introduce ``Node.fs_path`` as pathlib replacement for ``Node.fspath``. |
Also I would add another paragraph:
This is part of our continuous effort of eventually phasing out pytest's dependency to `py <https://py.readthedocs.io/en/latest/>`__.
src/_pytest/nodes.py
Outdated
| parent: Optional["Node"], | ||
| config: Optional[Config] = None, | ||
| session: "Optional[Session]" = None, | ||
| fspath: Optional[py.path.local] = None, |
There was a problem hiding this comment.
By dropping fspath (the py.path.local variant) aren't we breaking the API? If so I think a better option would be to still support fspath, converting it internally to fs_path and issue a deprecation warning.
| def fspath(self) -> py.path.local: | ||
| """Filesystem path where this node was collected from (can be None). | ||
|
|
||
| Since pytest 6.2, prefer to use `fs_path` instead which returns a `pathlib.Path` |
There was a problem hiding this comment.
| Since pytest 6.2, prefer to use `fs_path` instead which returns a `pathlib.Path` | |
| Since pytest 6.2, prefer to use `fs_path` instead which returns a :class:`pathlib.Path` |
|
the overall input here has convinced me to do the extra work of extraction and splitting originally i planned to simplify things by dropping implication at the same time, but all i accomplished is learning that i had to bring it back, so im going to reiterate today and take what i learned to do a number of prs to make things prettier |
as PyObjMixin is always supposed to be mixed in the mro before nodes.Node the behavior doesn't change, but all the typing information carry over to help mypy. extracted from pytest-dev#8037
as PyObjMixin is always supposed to be mixed in the mro before nodes.Node the behavior doesn't change, but all the typing information carry over to help mypy. extracted from pytest-dev#8037
as PyObjMixin is always supposed to be mixed in the mro before nodes.Node the behavior doesn't change, but all the typing information carry over to help mypy. extracted from pytest-dev#8037
|
closing as resolved in other prs by me, thanks for the help |
@pytest-dev/core with this i'm starting my continuation of the removal of both, too smart ctors annd migrating fspath to a pathlib version
its going to be a draft for a while while i iterate and figure the exact details, please scrutinize meanwhile ^^