Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migrate node fs paths to pathlib primary and reorg ctors/from_parent #8037

Closed

Conversation

RonnyPfannschmidt
Copy link
Member

@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 ^^

@RonnyPfannschmidt RonnyPfannschmidt added topic: collection related to the collection phase type: backward compatibility might present some backward compatibility issues which should be carefully noted in the changelog labels Nov 15, 2020
@RonnyPfannschmidt
Copy link
Member Author

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

@RonnyPfannschmidt RonnyPfannschmidt requested review from nicoddemus, bluetech and asottile and removed request for nicoddemus November 15, 2020 20:25
@RonnyPfannschmidt
Copy link
Member Author

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

@RonnyPfannschmidt RonnyPfannschmidt added the type: removal marks the actual removal of a feature, usually done in major releases label Nov 15, 2020
Copy link
Member

@asottile asottile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 👍

Copy link
Member

@nicoddemus nicoddemus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall is looking good! Left a few comments. 👍


#: Filesystem path where this node was collected from (can be None).
self.fspath = fspath or getattr(parent, "fspath", None)
self.fs_path = fs_path
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about file_path? This is always a file right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

relto is from py.path.local - relative pathlib paths are relative

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see, thanks, but does the comment about name.replace still apply?

>>> local("src/pytest").relto(local("."))
'src\\pytest'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it does

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice

assert parent is not None
session = parent.session
relp = session._bestrelpathcache[known_path]
if not relp.startswith(".." + os.sep):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we have a comment here explaining the purpose of this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gentle ping

Copy link
Member

@bluetech bluetech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a full review, just some comment.

@@ -458,7 +458,12 @@ class Session(nodes.FSCollector):

def __init__(self, config: Config) -> None:
super().__init__(
config.rootdir, parent=None, config=config, session=self, nodeid=""
fs_path=Path(config.rootdir),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fs_path=Path(config.rootdir),
fs_path=config.rootpath,

key = (type(x), x.fspath)
if key in node_cache2:
yield node_cache2[key]
keya = (type(x), x.fspath)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest key2 to match node_cache2.

key = (type(node), node.nodeid)
if key in matchnodes_cache:
rep = matchnodes_cache[key]
keyb = (type(node), str(node.nodeid))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here I would call it key_matchnodes.

Why is the str(node.nodeid) needed? Isn't nodeid already an str?


#: Filesystem path where this node was collected from (can be None).
self.fspath = fspath or getattr(parent, "fspath", None)
self.fs_path = fs_path
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@RonnyPfannschmidt RonnyPfannschmidt changed the title migrate node fs paths to pathlib primary and reor ctors/from_parent migrate node fs paths to pathlib primary and reorg ctors/from_parent Nov 22, 2020
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest-flakes that referenced this pull request Nov 23, 2020
@RonnyPfannschmidt
Copy link
Member Author

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

cc @nicoddemus @bluetech @asottile

@nicoddemus
Copy link
Member

Cool thanks for the follow up

im thinking of reintroducing implying for a little while...

Not sure I follow can you please clarify that?

@RonnyPfannschmidt
Copy link
Member Author

Aka having the node ctors imply things and warning about it so plugins can migrate

@nicoddemus
Copy link
Member

Ahh got it, thanks!

@RonnyPfannschmidt
Copy link
Member Author

@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

@nicoddemus
Copy link
Member

fragile base class

What you mean exactly, in terms of the number of arguments that can be passed?

im thinking of reintroducing implying for a little while and using the pytest-flakes pr as a example for propper ctors

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.

@RonnyPfannschmidt
Copy link
Member Author

@nicoddemus hitting another case of rebase demonstrating why primarily acceptance tests is a massive problem, will debug sometime later

@RonnyPfannschmidt RonnyPfannschmidt force-pushed the fspath-as-pathlib branch 2 times, most recently from 576997a to 6934346 Compare January 4, 2021 23:59
@RonnyPfannschmidt RonnyPfannschmidt marked this pull request as ready for review January 15, 2021 21:35
Copy link
Member

@bluetech bluetech left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be easier to evaluate this PR if it were split into at least two parts:

  1. The implied-arguments deprecation
  2. 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).

"_nodeid",
"_store",
"__dict__",
)

name: str
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. 👍

Comment on lines +69 to +70
"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",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"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,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one i missed while restoring ctor based implication

@@ -0,0 +1 @@
Introduce ``Node.fs_path`` as pathlib replacement for ``Node.fspath``
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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/>`__.

config: Optional[Config] = None,
session: "Optional[Session]" = None,
fspath: Optional[py.path.local] = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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`

@RonnyPfannschmidt
Copy link
Member Author

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

RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Jan 17, 2021
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
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Jan 17, 2021
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
RonnyPfannschmidt added a commit to RonnyPfannschmidt/pytest that referenced this pull request Jan 17, 2021
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
Base automatically changed from master to main March 9, 2021 20:40
@RonnyPfannschmidt
Copy link
Member Author

closing as resolved in other prs by me, thanks for the help

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
topic: collection related to the collection phase type: backward compatibility might present some backward compatibility issues which should be carefully noted in the changelog type: removal marks the actual removal of a feature, usually done in major releases
Projects
Status: discarded
Development

Successfully merging this pull request may close these issues.

4 participants