diff --git a/CHANGELOG b/CHANGELOG index e362a23e0..06d43a305 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,10 @@ Changes between 2.4.1 and 2.4.2 ----------------------------------- +- fix "-k" matching of tests where "repr" and "attr" and other names would + cause wrong matches because of an internal implementation quirk + (don't ask) which is now properly implemented. fixes issue345. + - avoid "IOError: Bad Filedescriptor" on pytest shutdown by not closing the internal dupped stdout (fix is slightly hand-wavy but work). diff --git a/_pytest/main.py b/_pytest/main.py index 61095f62f..4cca93ff1 100644 --- a/_pytest/main.py +++ b/_pytest/main.py @@ -170,30 +170,39 @@ def compatproperty(name): class NodeKeywords(MappingMixin): def __init__(self, node): - parent = node.parent - bases = parent and (parent.keywords._markers,) or () - self._markers = type("dynmarker", bases, {node.name: True}) + self.node = node + self.parent = node.parent + self._markers = {node.name: True} def __getitem__(self, key): try: - return getattr(self._markers, key) - except AttributeError: - raise KeyError(key) + return self._markers[key] + except KeyError: + if self.parent is None: + raise + return self.parent.keywords[key] def __setitem__(self, key, value): - setattr(self._markers, key, value) + self._markers[key] = value def __delitem__(self, key): - delattr(self._markers, key) + raise ValueError("cannot delete key in keywords dict") def __iter__(self): - return iter(self.keys()) + seen = set(self._markers) + if self.parent is not None: + seen.update(self.parent.keywords) + return iter(seen) def __len__(self): - return len(self.keys()) + return len(self.__iter__()) def keys(self): - return dir(self._markers) + return list(self) + + def __repr__(self): + return "" % (self.node, ) + class Node(object): """ base class for Collector and Item the test collection tree. diff --git a/bench/bench.py b/bench/bench.py index c9644ef61..8120f9f67 100644 --- a/bench/bench.py +++ b/bench/bench.py @@ -7,4 +7,4 @@ if __name__ == '__main__': p = pstats.Stats("prof") p.strip_dirs() p.sort_stats('cumulative') - print(p.print_stats(30)) + print(p.print_stats(50)) diff --git a/testing/test_collection.py b/testing/test_collection.py index c27bad957..5a1e9a052 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -566,4 +566,25 @@ def test_matchnodes_two_collections_same_file(testdir): ]) +class TestNodekeywords: + def test_no_under(self, testdir): + modcol = testdir.getmodulecol(""" + def test_pass(): pass + def test_fail(): assert 0 + """) + l = list(modcol.keywords) + assert modcol.name in l + for x in l: + assert not x.startswith("_") + assert modcol.name in repr(modcol.keywords) + def test_issue345(self, testdir): + testdir.makepyfile(""" + def test_should_not_be_selected(): + assert False, 'I should not have been selected to run' + + def test___repr__(): + pass + """) + reprec = testdir.inline_run("-k repr") + reprec.assertoutcome(passed=1, failed=0)