Skip to content

Commit e077f1c

Browse files
authored
Merge pull request #9168 from bluetech/node-keywords-dups
mark/structures: fix NodeKeywords.{__iter__,__len__} given duplicates
2 parents c9267af + cf4495f commit e077f1c

File tree

2 files changed

+26
-5
lines changed

2 files changed

+26
-5
lines changed

src/_pytest/mark/structures.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -579,14 +579,17 @@ def __delitem__(self, key: str) -> None:
579579
raise ValueError("cannot delete key in keywords dict")
580580

581581
def __iter__(self) -> Iterator[str]:
582+
# Doesn't need to be fast.
582583
yield from self._markers
583584
if self.parent is not None:
584-
yield from self.parent.keywords
585+
for keyword in self.parent.keywords:
586+
# self._marks and self.parent.keywords can have duplicates.
587+
if keyword not in self._markers:
588+
yield keyword
585589

586590
def __len__(self) -> int:
587-
return len(self._markers) + (
588-
len(self.parent.keywords) if self.parent is not None else 0
589-
)
591+
# Doesn't need to be fast.
592+
return sum(1 for keyword in self)
590593

591594
def __repr__(self) -> str:
592595
return f"<NodeKeywords for node {self.node}>"

testing/test_collection.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -793,7 +793,7 @@ def runtest(self):
793793
res.stdout.fnmatch_lines(["*1 passed*"])
794794

795795

796-
class TestNodekeywords:
796+
class TestNodeKeywords:
797797
def test_no_under(self, pytester: Pytester) -> None:
798798
modcol = pytester.getmodulecol(
799799
"""
@@ -859,6 +859,24 @@ def test_failing_5():
859859
reprec = pytester.inline_run("-k " + expression)
860860
reprec.assertoutcome(passed=num_matching_tests, failed=0)
861861

862+
def test_duplicates_handled_correctly(self, pytester: Pytester) -> None:
863+
item = pytester.getitem(
864+
"""
865+
import pytest
866+
pytestmark = pytest.mark.kw
867+
class TestClass:
868+
pytestmark = pytest.mark.kw
869+
def test_method(self): pass
870+
test_method.kw = 'method'
871+
""",
872+
"test_method",
873+
)
874+
assert item.parent is not None and item.parent.parent is not None
875+
item.parent.parent.keywords["kw"] = "class"
876+
877+
assert item.keywords["kw"] == "method"
878+
assert len(item.keywords) == len(set(item.keywords))
879+
862880

863881
COLLECTION_ERROR_PY_FILES = dict(
864882
test_01_failure="""

0 commit comments

Comments
 (0)