Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/_pytest/config/findpaths.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import os
from pathlib import Path
import sys
import tempfile
from typing import TypeAlias

import iniconfig
Expand Down Expand Up @@ -221,6 +222,15 @@ def determine_setup(
if rootdir is None and rootdir_cmd_arg is None:
for possible_rootdir in (ancestor, *ancestor.parents):
if (possible_rootdir / "setup.py").is_file():
# Skip setup.py in temp directory to avoid false positives
# (see issue #13822)
try:
temp_dir = Path(tempfile.gettempdir()).resolve()
if possible_rootdir.resolve() == temp_dir:
continue
except (OSError, ValueError):
# If we can't resolve paths, continue with normal behavior
pass
rootdir = possible_rootdir
break
else:
Expand Down
70 changes: 70 additions & 0 deletions testing/test_findpaths.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@

import os
from pathlib import Path
import tempfile
from textwrap import dedent

from _pytest.config import UsageError
from _pytest.config.findpaths import determine_setup
from _pytest.config.findpaths import get_common_ancestor
from _pytest.config.findpaths import get_dirs_from_args
from _pytest.config.findpaths import is_fs_root
Expand Down Expand Up @@ -154,3 +156,71 @@ def test_get_dirs_from_args(tmp_path):
)
def test_is_fs_root(path: Path, expected: bool) -> None:
assert is_fs_root(Path(path)) is expected


class TestDetermineSetup:
def test_ignore_setup_py_in_temp_dir(self, tmp_path: Path) -> None:
"""Test that setup.py in the temp directory is ignored for rootdir detection.

This addresses issue #13822 where a setup.py file in /tmp would cause
pytest to incorrectly identify /tmp as the rootdir.
"""
# Check if /tmp/setup.py exists (it should for this test to be meaningful)
real_temp_dir = Path(tempfile.gettempdir())
temp_setup_file = real_temp_dir / "setup.py"
temp_setup_existed = temp_setup_file.exists()

# Ensure setup.py exists in temp directory for the test
if not temp_setup_existed:
temp_setup_file.write_text("# temp setup.py for test")

try:
# Create a project directory that would be inside temp hierarchy
# Simulate a pytest temp directory structure
project_dir = tmp_path / "project"
project_dir.mkdir()

test_file = project_dir / "test_example.py"
test_file.write_text("def test_example(): pass")

# Test case: running pytest from a directory that could traverse up to /tmp
# If our fix is working, it should NOT use /tmp as rootdir even though
# /tmp/setup.py exists
rootdir, inipath, inicfg, ignored = determine_setup(
inifile=None,
args=[str(test_file)],
rootdir_cmd_arg=None,
invocation_dir=project_dir,
)

# The rootdir should not be the temp directory, even if setup.py exists there
assert rootdir != real_temp_dir
# Should default to the project directory or its parent
assert rootdir in (project_dir, project_dir.parent)

finally:
# Clean up the temp setup.py if we created it
if not temp_setup_existed and temp_setup_file.exists():
temp_setup_file.unlink()

def test_normal_setup_py_detection_still_works(self, tmp_path: Path) -> None:
"""Test that normal setup.py detection still works after our fix."""
# Create a project with setup.py
project_dir = tmp_path / "my_project"
project_dir.mkdir()

setup_file = project_dir / "setup.py"
setup_file.write_text("from setuptools import setup; setup()")

test_file = project_dir / "test_example.py"
test_file.write_text("def test_example(): pass")

# Test that setup.py is still found normally
rootdir, inipath, inicfg, ignored = determine_setup(
inifile=None,
args=[str(test_file)],
rootdir_cmd_arg=None,
invocation_dir=project_dir,
)

assert rootdir == project_dir
Loading