Skip to content

Commit b131214

Browse files
authored
Merge pull request #4358 from blueyed/instance
Node: do not add "::()" to nodeid
2 parents 10d27f4 + f551cb9 commit b131214

File tree

8 files changed

+50
-30
lines changed

8 files changed

+50
-30
lines changed

changelog/4358.removal.rst

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Remove the ``::()`` notation to denote a test class instance in node ids.
2+
3+
Previously, node ids that contain test instances would use ``::()`` to denote the instance like this::
4+
5+
test_foo.py::Test::()::test_bar
6+
7+
The extra ``::()`` was puzzling to most users and has been removed, so that the test id becomes now::
8+
9+
test_foo.py::Test::test_bar
10+
11+
This change could not accompany a deprecation period as is usual when user-facing functionality changes because
12+
it was not really possible to detect when the functionality was being used explicitly.
13+
14+
The extra ``::()`` might have been removed in some places internally already,
15+
which then led to confusion in places where it was expected, e.g. with
16+
``--deselect`` (`#4127 <https://github.com/pytest-dev/pytest/issues/4127>`_).
17+
18+
Test class instances are also not listed with ``--collect-only`` anymore.

src/_pytest/nodes.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def _splitnode(nodeid):
2727
''
2828
'testing/code'
2929
'testing/code/test_excinfo.py'
30-
'testing/code/test_excinfo.py::TestFormattedExcinfo::()'
30+
'testing/code/test_excinfo.py::TestFormattedExcinfo'
3131
3232
Return values are lists e.g.
3333
[]
@@ -39,15 +39,15 @@ def _splitnode(nodeid):
3939
# If there is no root node at all, return an empty list so the caller's logic can remain sane
4040
return []
4141
parts = nodeid.split(SEP)
42-
# Replace single last element 'test_foo.py::Bar::()' with multiple elements 'test_foo.py', 'Bar', '()'
42+
# Replace single last element 'test_foo.py::Bar' with multiple elements 'test_foo.py', 'Bar'
4343
parts[-1:] = parts[-1].split("::")
4444
return parts
4545

4646

4747
def ischildnode(baseid, nodeid):
4848
"""Return True if the nodeid is a child node of the baseid.
4949
50-
E.g. 'foo/bar::Baz::()' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp'
50+
E.g. 'foo/bar::Baz' is a child of 'foo', 'foo/bar' and 'foo/bar::Baz', but not of 'foo/blorp'
5151
"""
5252
base_parts = _splitnode(baseid)
5353
node_parts = _splitnode(nodeid)
@@ -107,10 +107,12 @@ def __init__(
107107
self._name2pseudofixturedef = {}
108108

109109
if nodeid is not None:
110+
assert "::()" not in nodeid
110111
self._nodeid = nodeid
111112
else:
112-
assert parent is not None
113-
self._nodeid = self.parent.nodeid + "::" + self.name
113+
self._nodeid = self.parent.nodeid
114+
if self.name != "()":
115+
self._nodeid += "::" + self.name
114116

115117
@property
116118
def ihook(self):

src/_pytest/runner.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,7 @@ def pytest_terminal_summary(terminalreporter):
6060
tr.write_line("")
6161
tr.write_line("(0.00 durations hidden. Use -vv to show these durations.)")
6262
break
63-
nodeid = rep.nodeid.replace("::()::", "::")
64-
tr.write_line("%02.2fs %-8s %s" % (rep.duration, rep.when, nodeid))
63+
tr.write_line("%02.2fs %-8s %s" % (rep.duration, rep.when, rep.nodeid))
6564

6665

6766
def pytest_sessionstart(session):

src/_pytest/terminal.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -605,9 +605,7 @@ def _printcollecteditems(self, items):
605605
self._tw.line("%s: %d" % (name, count))
606606
else:
607607
for item in items:
608-
nodeid = item.nodeid
609-
nodeid = nodeid.replace("::()::", "::")
610-
self._tw.line(nodeid)
608+
self._tw.line(item.nodeid)
611609
return
612610
stack = []
613611
indent = ""
@@ -619,8 +617,8 @@ def _printcollecteditems(self, items):
619617
stack.pop()
620618
for col in needed_collectors[len(stack) :]:
621619
stack.append(col)
622-
# if col.name == "()":
623-
# continue
620+
if col.name == "()": # Skip Instances.
621+
continue
624622
indent = (len(stack) - 1) * " "
625623
self._tw.line("%s%s" % (indent, col))
626624

@@ -687,7 +685,7 @@ def mkrel(nodeid):
687685
# collect_fspath comes from testid which has a "/"-normalized path
688686

689687
if fspath:
690-
res = mkrel(nodeid).replace("::()", "") # parens-normalization
688+
res = mkrel(nodeid)
691689
if self.verbosity >= 2 and nodeid.split("::")[0] != fspath.replace(
692690
"\\", nodes.SEP
693691
):

testing/python/collect.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,9 +1408,7 @@ def test_hello(self):
14081408
"""
14091409
)
14101410
result = testdir.runpytest("--collect-only")
1411-
result.stdout.fnmatch_lines(
1412-
["*MyClass*", "*MyInstance*", "*MyFunction*test_hello*"]
1413-
)
1411+
result.stdout.fnmatch_lines(["*MyClass*", "*MyFunction*test_hello*"])
14141412

14151413

14161414
def test_unorderable_types(testdir):

testing/test_collection.py

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -510,13 +510,8 @@ def test_method(self):
510510
pass
511511
"""
512512
)
513-
normid = p.basename + "::TestClass::()::test_method"
514-
for id in [
515-
p.basename,
516-
p.basename + "::TestClass",
517-
p.basename + "::TestClass::()",
518-
normid,
519-
]:
513+
normid = p.basename + "::TestClass::test_method"
514+
for id in [p.basename, p.basename + "::TestClass", normid]:
520515
items, hookrec = testdir.inline_genitems(id)
521516
assert len(items) == 1
522517
assert items[0].name == "test_method"
@@ -625,7 +620,7 @@ def test_method(self):
625620
items, hookrec = testdir.inline_genitems(arg)
626621
assert len(items) == 1
627622
item, = items
628-
assert item.nodeid.endswith("TestClass::()::test_method")
623+
assert item.nodeid.endswith("TestClass::test_method")
629624
# ensure we are reporting the collection of the single test item (#2464)
630625
assert [x.name for x in self.get_reported_items(hookrec)] == ["test_method"]
631626

testing/test_nodes.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88
("", "", True),
99
("", "foo", True),
1010
("", "foo/bar", True),
11-
("", "foo/bar::TestBaz::()", True),
11+
("", "foo/bar::TestBaz", True),
1212
("foo", "food", False),
13-
("foo/bar::TestBaz::()", "foo/bar", False),
14-
("foo/bar::TestBaz::()", "foo/bar::TestBop::()", False),
15-
("foo/bar", "foo/bar::TestBop::()", True),
13+
("foo/bar::TestBaz", "foo/bar", False),
14+
("foo/bar::TestBaz", "foo/bar::TestBop", False),
15+
("foo/bar", "foo/bar::TestBop", True),
1616
),
1717
)
1818
def test_ischildnode(baseid, nodeid, expected):

testing/test_session.py

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,16 +274,26 @@ def test_deselect(testdir):
274274
testdir.makepyfile(
275275
test_a="""
276276
import pytest
277+
277278
def test_a1(): pass
279+
278280
@pytest.mark.parametrize('b', range(3))
279281
def test_a2(b): pass
282+
283+
class TestClass:
284+
def test_c1(self): pass
285+
286+
def test_c2(self): pass
280287
"""
281288
)
282289
result = testdir.runpytest(
283-
"-v", "--deselect=test_a.py::test_a2[1]", "--deselect=test_a.py::test_a2[2]"
290+
"-v",
291+
"--deselect=test_a.py::test_a2[1]",
292+
"--deselect=test_a.py::test_a2[2]",
293+
"--deselect=test_a.py::TestClass::test_c1",
284294
)
285295
assert result.ret == 0
286-
result.stdout.fnmatch_lines(["*2 passed, 2 deselected*"])
296+
result.stdout.fnmatch_lines(["*3 passed, 3 deselected*"])
287297
for line in result.stdout.lines:
288298
assert not line.startswith(("test_a.py::test_a2[1]", "test_a.py::test_a2[2]"))
289299

0 commit comments

Comments
 (0)