pytest-dev / pytest-dev/pytest

Same named test functions in different `Pytester` tests will use the same `tmp_path` location

Open
#12,731 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

plugin: pytester
Dominant language
Python
Stars
14.5k
Forks
3.4k
Avg merge
2d 9h
Merged PRs (30d)
35

Description

If you setup Pytester tests that uses tmp_path then they will share directory if named the same, even if run in different tests. This only happens when run with runpytest not inline_run. So when running this code:

def test_1(pytester: Pytester):
    pytester.makepyfile(
        """
        def test(tmp_path):
            assert False
    """
    )
    pytester.runpytest()


def test_2(pytester: Pytester):
    pytester.makepyfile(
        """
        def test(tmp_path):
            assert False

    """
    )
    pytester.runpytest()

both inner test functions will have tmp_path pointing to the same directory.

This might not be a bug outright since I don't think pytester makes any claim for this not to happen, but I think it's a major footgun for using pytester.

Below is a full reproduction that shows the paths are indeed the same in the given situations. When this is run, the fixture will throw an error for TestRunPytest

from pytest import Pytester
import pytest
import re


@pytest.fixture(scope="class")
def extract_and_compare_temp_path():
    paths = []
    def _saver(lines):
        for line in lines:
            if match := re.match(r"tmp_path = PosixPath.'(.*)'.", line):
                paths.append(match.group(1))
    yield _saver
    # The paths should not be the same
    assert paths[0] != paths[1]

class TestRunPytest: # both test functions uses the same test path
    def test_1(self, pytester: Pytester, extract_and_compare_temp_path):
        pytester.makepyfile(
            """
            def test(tmp_path):
                assert False
        """
        )

        path = pytester.runpytest().outlines
        extract_and_compare_temp_path(path)


    def test_2(self, pytester: Pytester, extract_and_compare_temp_path):
        pytester.makepyfile(
            """
            def test(tmp_path):
                assert False

        """
        )
        path = pytester.runpytest().outlines
        extract_and_compare_temp_path(path)

class TestRunPytestDifferentFunctionNames: # does not same tmp_path
    def test_1(self, pytester: Pytester, extract_and_compare_temp_path):
        pytester.makepyfile(
            """
            def test(tmp_path):
                assert False
        """
        )

        path = pytester.runpytest().outlines
        extract_and_compare_temp_path(path)


    def test_2(self, pytester: Pytester, extract_and_compare_temp_path):
        pytester.makepyfile(
            """
            def test_with_other_name(tmp_path):
                assert False

        """
        )
        path = pytester.runpytest().outlines
        extract_and_compare_temp_path(path)

class TestInlineRun: # These have the different temp paths
    def test_1(self, pytester: Pytester, extract_and_compare_temp_path):
        pytester.makepyfile(
            """
            def test(tmp_path):
                assert False
        """
        )

        path = pytester.inline_run().getfailures()[0]
        extract_and_compare_temp_path([path.longreprtext])


    def test_2(self, pytester: Pytester, extract_and_compare_temp_path):
        pytester.makepyfile(
            """
            def test(tmp_path):
                assert False

        """
        )

        path = pytester.inline_run().getfailures()[0]
        extract_and_compare_temp_path([path.longreprtext])

Env: platform linux -- Python 3.12.5, pytest-8.3.2, pluggy-1.5.0

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Pytester behavior exercised by the reported runpytest reproduction, and compare it with inline_run, which already produces different paths. Trace how the inner test name contributes to tmp_path allocation. Done means same-named inner tests invoked through separate runpytest calls receive distinct tmp_path locations, with a regression test covering the reproduction.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.