diff --git a/changelog/7040.breaking.rst b/changelog/7040.breaking.rst new file mode 100644 index 000000000..897b2c0a9 --- /dev/null +++ b/changelog/7040.breaking.rst @@ -0,0 +1,6 @@ +``-k`` no longer matches against the names of the directories outside the test session root. + +Also, ``pytest.Package.name`` is now just the name of the directory containing the package's +``__init__.py`` file, instead of the full path. This is consistent with how the other nodes +are named, and also one of the reasons why ``-k`` would match against any directory containing +the test suite. diff --git a/src/_pytest/mark/__init__.py b/src/_pytest/mark/__init__.py index 242b1e0ca..1cd6e74c9 100644 --- a/src/_pytest/mark/__init__.py +++ b/src/_pytest/mark/__init__.py @@ -136,7 +136,7 @@ class KeywordMatcher: import pytest for item in item.listchain(): - if not isinstance(item, pytest.Instance): + if not isinstance(item, (pytest.Instance, pytest.Session)): mapped_names.add(item.name) # Add the names added as extra keywords to current or parent items diff --git a/src/_pytest/python.py b/src/_pytest/python.py index 0613e6eda..76fccb4a1 100644 --- a/src/_pytest/python.py +++ b/src/_pytest/python.py @@ -571,8 +571,7 @@ class Package(Module): nodes.FSCollector.__init__( self, fspath, parent=parent, config=config, session=session, nodeid=nodeid ) - - self.name = fspath.dirname + self.name = os.path.basename(str(fspath.dirname)) def setup(self): # not using fixtures to call setup_module here because autouse fixtures diff --git a/testing/test_collection.py b/testing/test_collection.py index 2fd832dc6..dfbfe9ba8 100644 --- a/testing/test_collection.py +++ b/testing/test_collection.py @@ -1004,7 +1004,7 @@ def test_collect_init_tests(testdir): result.stdout.fnmatch_lines( [ "collected 2 items", - "", " ", " ", " ", @@ -1015,7 +1015,7 @@ def test_collect_init_tests(testdir): result.stdout.fnmatch_lines( [ "collected 2 items", - "", " ", " ", " ", @@ -1027,7 +1027,7 @@ def test_collect_init_tests(testdir): result.stdout.fnmatch_lines( [ "collected 2 items", - "", + "", " ", " ", " ", @@ -1039,7 +1039,7 @@ def test_collect_init_tests(testdir): result.stdout.fnmatch_lines( [ "collected 2 items", - "", + "", " ", " ", " ", @@ -1048,12 +1048,12 @@ def test_collect_init_tests(testdir): ) result = testdir.runpytest("./tests/test_foo.py", "--collect-only") result.stdout.fnmatch_lines( - ["", " ", " "] + ["", " ", " "] ) result.stdout.no_fnmatch_line("*test_init*") result = testdir.runpytest("./tests/__init__.py", "--collect-only") result.stdout.fnmatch_lines( - ["", " ", " "] + ["", " ", " "] ) result.stdout.no_fnmatch_line("*test_foo*") diff --git a/testing/test_mark.py b/testing/test_mark.py index 1c983b5af..c14f770da 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -834,6 +834,36 @@ class TestKeywordSelection: deselected_tests = dlist[0].items assert len(deselected_tests) == 1 + def test_no_match_directories_outside_the_suite(self, testdir): + """ + -k should not match against directories containing the test suite (#7040). + """ + test_contents = """ + def test_aaa(): pass + def test_ddd(): pass + """ + testdir.makepyfile( + **{"ddd/tests/__init__.py": "", "ddd/tests/test_foo.py": test_contents} + ) + + def get_collected_names(*args): + _, rec = testdir.inline_genitems(*args) + calls = rec.getcalls("pytest_collection_finish") + assert len(calls) == 1 + return [x.name for x in calls[0].session.items] + + # sanity check: collect both tests in normal runs + assert get_collected_names() == ["test_aaa", "test_ddd"] + + # do not collect anything based on names outside the collection tree + assert get_collected_names("-k", testdir.tmpdir.basename) == [] + + # "-k ddd" should only collect "test_ddd", but not + # 'test_aaa' just because one of its parent directories is named "ddd"; + # this was matched previously because Package.name would contain the full path + # to the package + assert get_collected_names("-k", "ddd") == ["test_ddd"] + class TestMarkDecorator: @pytest.mark.parametrize(