-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
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
Issue 2836 fixture collection bug #2862
Changes from 6 commits
29fa9d5
c03612f
1e6dc6f
f003914
de9d116
ee7e1c9
d714c19
a7199fa
655ab0b
a3ec3df
14e3a5f
a5ac19c
f5e72d2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1130,7 +1130,40 @@ def getfixturedefs(self, argname, nodeid): | |
else: | ||
return tuple(self._matchfactories(fixturedefs, nodeid)) | ||
|
||
@classmethod | ||
def _splitnode(cls, nodeid): | ||
"""Split a nodeid into constituent 'parts'. | ||
|
||
Node IDs are strings, and can be things like: | ||
'', | ||
'testing/code', | ||
'testing/code/test_excinfo.py' | ||
'testing/code/test_excinfo.py::TestFormattedExcinfo::()' | ||
|
||
""" | ||
if nodeid == '': | ||
return [] | ||
sep = py.path.local.sep | ||
parts = nodeid.split(sep) | ||
last_part = parts[-1] | ||
if '::' in last_part: | ||
# Replace single last element 'test_foo.py::Bar::()' with multiple elements 'test_foo.py', 'Bar', '()' | ||
parts[-1:] = last_part.split("::") | ||
return parts | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just a suggestion to simplify the code: remove the special case for the empty
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks, I've shortened this down a bit (and made the docstring longer to compensate ;-)) |
||
|
||
@classmethod | ||
def _ischildnode(cls, baseid, nodeid): | ||
"""Return True if the nodeid is a child node of the baseid. | ||
|
||
E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp' | ||
""" | ||
base_parts = cls._splitnode(baseid) | ||
node_parts = cls._splitnode(nodeid) | ||
if len(node_parts) < len(base_parts): | ||
return False | ||
return node_parts[:len(base_parts)] == base_parts | ||
|
||
def _matchfactories(self, fixturedefs, nodeid): | ||
for fixturedef in fixturedefs: | ||
if nodeid.startswith(fixturedef.baseid): | ||
if self._ischildnode(fixturedef.baseid, nodeid): | ||
yield fixturedef |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
Attempted fix for https://github.com/pytest-dev/pytest/issues/2836 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i propose CC @nicoddemus |
||
|
||
Improves the handling of "nodeid"s to be more aware of path and class separators. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import pytest | ||
|
||
from _pytest import fixtures | ||
|
||
|
||
@pytest.mark.parametrize("baseid, nodeid, expected", ( | ||
('', '', True), | ||
('', 'foo', True), | ||
('', 'foo/bar', True), | ||
('', 'foo/bar::TestBaz::()', True), | ||
('foo', 'food', False), | ||
('foo/bar::TestBaz::()', 'foo/bar', False), | ||
('foo/bar::TestBaz::()', 'foo/bar::TestBop::()', False), | ||
('foo/bar', 'foo/bar::TestBop::()', True), | ||
)) | ||
def test_fixturemanager_ischildnode(baseid, nodeid, expected): | ||
result = fixtures.FixtureManager._ischildnode(baseid, nodeid) | ||
assert result is expected |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that this can be a
staticmethod
instead. The class isn't referenced anywhere in this method.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a fan of staticmethods, though mainly for inheritance related reasons and doubt anyone is subclassing fixtruemanager, let alone doing so and then wanting to change these. It feels like they should probably be plain functions in a 'node' module somewhere but hopefully someone more familiar with pytest can guide me on that... (see also my comment about
_splitnode
in the description).There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since both helpers are completely unrelated to the class, how about just moving them out of the class instead