From d5032d5c605ed7095d8b11274b7b0605a30ed395 Mon Sep 17 00:00:00 2001 From: Aditya Mehra Date: Sat, 18 Oct 2025 17:43:25 -0400 Subject: [PATCH 1/4] Fix: Skip system temp directories in rootdir detection (issue #13822) - Add helper function _is_system_temp_or_parent() to detect system temp dir - Modify determine_setup() to skip /tmp when searching for setup.py - Prevents pytest from incorrectly using /tmp as rootdir when /tmp/setup.py exists Fixes #13822 --- src/_pytest/config/findpaths.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/_pytest/config/findpaths.py b/src/_pytest/config/findpaths.py index 3f08c8121a9..7a0be474924 100644 --- a/src/_pytest/config/findpaths.py +++ b/src/_pytest/config/findpaths.py @@ -5,6 +5,7 @@ import os from pathlib import Path import sys +import tempfile from typing import TypeAlias import iniconfig @@ -184,6 +185,27 @@ def get_dir_from_path(path: Path) -> Path: CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supported, change to [tool:pytest] instead." +def _is_system_temp_or_parent(path: Path) -> bool: + """Check if path is the system temp directory. + + This prevents pytest from treating /tmp as a valid rootdir when + a /tmp/setup.py file exists on the system. + + Args: + path: The path to check + + Returns: + True if path is the system temp directory, False otherwise + """ + try: + system_temp = Path(tempfile.gettempdir()).resolve() + path = path.resolve() + # Skip exact matches with the system temp directory + return path == system_temp + except (OSError, RuntimeError): + # If we can't resolve paths, play it safe and don't skip + return False + def determine_setup( *, inifile: str | None, @@ -220,6 +242,9 @@ def determine_setup( ) if rootdir is None and rootdir_cmd_arg is None: for possible_rootdir in (ancestor, *ancestor.parents): + # Skip system temp directories to avoid false positives (issue #13822) + if _is_system_temp_or_parent(possible_rootdir): + continue if (possible_rootdir / "setup.py").is_file(): rootdir = possible_rootdir break From 98886a86cd4b437d45e606b0800402aad4117bf0 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sat, 18 Oct 2025 21:45:18 +0000 Subject: [PATCH 2/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/_pytest/config/findpaths.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/_pytest/config/findpaths.py b/src/_pytest/config/findpaths.py index 7a0be474924..baa322e15ee 100644 --- a/src/_pytest/config/findpaths.py +++ b/src/_pytest/config/findpaths.py @@ -206,6 +206,7 @@ def _is_system_temp_or_parent(path: Path) -> bool: # If we can't resolve paths, play it safe and don't skip return False + def determine_setup( *, inifile: str | None, From e2627045f994234b35c4f71a04f2131f1903b1ce Mon Sep 17 00:00:00 2001 From: Aditya Mehra Date: Mon, 20 Oct 2025 12:04:44 -0400 Subject: [PATCH 3/4] Add regression test for issue #13822 - Test verifies that setup.py in system temp dir is ignored - Uses monkeypatch to simulate /tmp/setup.py without touching system - Ensures rootdir detection works correctly --- testing/test_config.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/testing/test_config.py b/testing/test_config.py index 9efac8739b7..e1ae3a257ae 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1830,6 +1830,42 @@ def test_with_config_also_in_parent_directory( assert rootpath == tmp_path / "myproject" assert inipath == tmp_path / "myproject" / "setup.cfg" + def test_tmp_setup_py_does_not_affect_rootdir( + self, tmp_path: Path, monkeypatch: MonkeyPatch + ) -> None: + """Regression test for issue #13822. + + Ensure that setup.py in the system temp directory doesn't + affect rootdir detection. + """ + # Create a fake project structure + project = tmp_path / "my_project" + project.mkdir() + test_dir = project / "tests" + test_dir.mkdir() + + # Create project's own setup.py + (project / "setup.py").write_text("# project setup", "utf-8") + + # Monkeypatch tempfile.gettempdir() to simulate /tmp/setup.py existing + fake_temp = tmp_path / "fake_tmp" + fake_temp.mkdir() + (fake_temp / "setup.py").write_text("# tmp setup", "utf-8") + + monkeypatch.setattr("tempfile.gettempdir", lambda: str(fake_temp)) + monkeypatch.chdir(test_dir) + + rootpath, inipath, *_ = determine_setup( + inifile=None, + args=[str(test_dir)], + rootdir_cmd_arg=None, + invocation_dir=test_dir, + ) + + # Rootpath should be project, not fake temp + assert rootpath == project + assert rootpath != fake_temp + class TestOverrideIniArgs: @pytest.mark.parametrize("name", "setup.cfg tox.ini pytest.ini".split()) From 5df0db7e57506793c92a04b7e036eb5f07b0805e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:25:20 +0000 Subject: [PATCH 4/4] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- testing/test_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/test_config.py b/testing/test_config.py index e1ae3a257ae..4241de44fe4 100644 --- a/testing/test_config.py +++ b/testing/test_config.py @@ -1831,7 +1831,7 @@ def test_with_config_also_in_parent_directory( assert inipath == tmp_path / "myproject" / "setup.cfg" def test_tmp_setup_py_does_not_affect_rootdir( - self, tmp_path: Path, monkeypatch: MonkeyPatch + self, tmp_path: Path, monkeypatch: MonkeyPatch ) -> None: """Regression test for issue #13822.