From 4a1bba25b9ad23dccc00c695ffb4050b6ddb4189 Mon Sep 17 00:00:00 2001 From: Ran Benita Date: Sat, 27 May 2023 18:42:37 +0300 Subject: [PATCH] config: fallback confcutdir to rootpath if inipath is not set Currently, if `--confcutdir` is not set, `inipath.parent` is used, and if `initpath` is not set, then `confcutdir` is None, which means there is no cutoff. Having no cutoff is not great, it means we potentially start probing stuff all the way up to the filesystem root directory. So let's add another fallback, to `rootpath`, which is always something reasonable. --- changelog/11043.improvement.rst | 3 +++ src/_pytest/config/__init__.py | 7 +++++-- testing/test_config.py | 17 +++++++++++++++++ testing/test_conftest.py | 8 +++++++- 4 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 changelog/11043.improvement.rst diff --git a/changelog/11043.improvement.rst b/changelog/11043.improvement.rst new file mode 100644 index 00000000000..1fe0361d7f9 --- /dev/null +++ b/changelog/11043.improvement.rst @@ -0,0 +1,3 @@ +When `--confcutdir` is not specified, and there is no config file present, the conftest cutoff directory (`--confcutdir`) is now set to the :ref:`rootdir`. +Previously in such cases, `conftest.py` files would be probed all the way to the root directory of the filesystem. +If you are badly affected by this change, consider adding an empty config file to your desired cutoff directory, or explicitly set `--confcutdir`. diff --git a/src/_pytest/config/__init__.py b/src/_pytest/config/__init__.py index 6df06f7b281..c62be613523 100644 --- a/src/_pytest/config/__init__.py +++ b/src/_pytest/config/__init__.py @@ -1261,8 +1261,11 @@ def _preparse(self, args: List[str], addopts: bool = True) -> None: _pytest.deprecated.STRICT_OPTION, stacklevel=2 ) - if self.known_args_namespace.confcutdir is None and self.inipath is not None: - confcutdir = str(self.inipath.parent) + if self.known_args_namespace.confcutdir is None: + if self.inipath is not None: + confcutdir = str(self.inipath.parent) + else: + confcutdir = str(self.rootpath) self.known_args_namespace.confcutdir = confcutdir try: self.hook.pytest_load_initial_conftests( diff --git a/testing/test_config.py b/testing/test_config.py index 1291e85f9dd..cdeb67aceff 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -179,6 +179,23 @@ def test_toml_parse_error(self, pytester: Pytester) -> None: assert result.ret != 0 result.stderr.fnmatch_lines("ERROR: *pyproject.toml: Invalid statement*") + def test_confcutdir_default_without_configfile(self, pytester: Pytester) -> None: + # If --confcutdir is not specified, and there is no configfile, default + # to the roothpath. + sub = pytester.mkdir("sub") + os.chdir(sub) + config = pytester.parseconfigure() + assert config.pluginmanager._confcutdir == sub + + def test_confcutdir_default_with_configfile(self, pytester: Pytester) -> None: + # If --confcutdir is not specified, and there is a configfile, default + # to the configfile's directory. + pytester.makeini("[pytest]") + sub = pytester.mkdir("sub") + os.chdir(sub) + config = pytester.parseconfigure() + assert config.pluginmanager._confcutdir == pytester.path + @pytest.mark.xfail(reason="probably not needed") def test_confcutdir(self, pytester: Pytester) -> None: sub = pytester.mkdir("sub") diff --git a/testing/test_conftest.py b/testing/test_conftest.py index d6abca5368f..c64bd11d4ed 100644 --- a/testing/test_conftest.py +++ b/testing/test_conftest.py @@ -594,7 +594,13 @@ def test_parsefactories_relative_node_ids( print("pytestarg : %s" % testarg) print("expected pass : %s" % expect_ntests_passed) os.chdir(dirs[chdir]) - reprec = pytester.inline_run(testarg, "-q", "--traceconfig") + reprec = pytester.inline_run( + testarg, + "-q", + "--traceconfig", + "--confcutdir", + pytester.path, + ) reprec.assertoutcome(passed=expect_ntests_passed)