-
Notifications
You must be signed in to change notification settings - Fork 9
Description
Consider a test file named test_with_tmp_path_fixture.py that uses the tmp_path fixture:
def test_with_tmp_path(tmp_path):
assert tmp_path.exists()
assert tmp_path.is_dir()
assert len(list(tmp_path.iterdir())) == 0
d = tmp_path / "sub"
assert not d.exists()
d.mkdir()
assert d.exists()It's quite typical from such tests to assume that the folder generated by the fixture is empty when executed.
Running such a test with pytest-run-parallel will therefore fail either because of parallelism or repetition:
- parallelism (one execution per thread):
pytest -v --parallel-threads=4 --iterations=1 test_with_tmp_path_fixture.py
================================================================= test session starts ==================================================================
platform darwin -- Python 3.13.3, pytest-8.4.0, pluggy-1.6.0 -- /Users/ogrisel/miniforge3/envs/dev/bin/python3.13
cachedir: .pytest_cache
rootdir: /Users/ogrisel/tmp
plugins: run-parallel-0.6.1.dev0, xdist-3.7.0, anyio-4.9.0
collected 1 item
Collected 1 items to run in parallel
test_with_tmp_path_fixture.py::test_with_tmp_path PARALLEL FAILED [100%]
======================================================================== ERRORS ========================================================================
_________________________________________________________ ERROR at call of test_with_tmp_path __________________________________________________________
tmp_path = PosixPath('/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-15/test_with_tmp_path0')
def test_with_tmp_path(tmp_path):
assert tmp_path.exists()
assert tmp_path.is_dir()
assert len(list(tmp_path.iterdir())) == 0
d = tmp_path / "sub"
assert not d.exists()
> d.mkdir()
test_with_tmp_path_fixture.py:7:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = PosixPath('/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-15/test_with_tmp_path0/sub'), mode = 511
parents = False, exist_ok = False
def mkdir(self, mode=0o777, parents=False, exist_ok=False):
"""
Create a new directory at this given path.
"""
try:
> os.mkdir(self, mode)
E FileExistsError: [Errno 17] File exists: '/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-15/test_with_tmp_path0/sub'
../miniforge3/envs/dev/lib/python3.13/pathlib/_local.py:722: FileExistsError
************************************************************** pytest-run-parallel report **************************************************************
All tests were run in parallel! 🎉
=============================================================== short test summary info ================================================================
PARALLEL FAILED test_with_tmp_path_fixture.py::test_with_tmp_path - FileExistsError: [Errno 17] File exists: '/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-15/test_with_tmp_path0/...
=================================================================== 1 error in 0.10s ===================================================================
- sequential repetition:
pytest -v --parallel-threads=1 --iterations=2 test_with_tmp_path_fixture.py
================================================================= test session starts ==================================================================
platform darwin -- Python 3.13.3, pytest-8.4.0, pluggy-1.6.0 -- /Users/ogrisel/miniforge3/envs/dev/bin/python3.13
cachedir: .pytest_cache
rootdir: /Users/ogrisel/tmp
plugins: run-parallel-0.6.1.dev0, xdist-3.7.0, anyio-4.9.0
collected 1 item
Collected 0 items to run in parallel
test_with_tmp_path_fixture.py::test_with_tmp_path FAILED [100%]
======================================================================= FAILURES =======================================================================
__________________________________________________________________ test_with_tmp_path __________________________________________________________________
tmp_path = PosixPath('/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-16/test_with_tmp_path0')
def test_with_tmp_path(tmp_path):
assert tmp_path.exists()
assert tmp_path.is_dir()
> assert len(list(tmp_path.iterdir())) == 0
E AssertionError: assert 1 == 0
E + where 1 = len([PosixPath('/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-16/test_with_tmp_path0/sub')])
E + where [PosixPath('/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-16/test_with_tmp_path0/sub')] = list(<map object at 0x10c9704f0>)
E + where <map object at 0x10c9704f0> = iterdir()
E + where iterdir = PosixPath('/private/var/folders/93/0_k_9bh97fj_15hzk2bhy5r00000gn/T/pytest-of-ogrisel/pytest-16/test_with_tmp_path0').iterdir
test_with_tmp_path_fixture.py:4: AssertionError
=============================================================== short test summary info ================================================================
FAILED test_with_tmp_path_fixture.py::test_with_tmp_path - AssertionError: assert 1 == 0
================================================================== 1 failed in 0.35s ===================================================================
but this tests does pass as expected when disabling both parallelism and repetition together:
pytest -v --parallel-threads=1 --iterations=1 test_with_tmp_path_fixture.py
================================================================= test session starts ==================================================================
platform darwin -- Python 3.13.3, pytest-8.4.0, pluggy-1.6.0 -- /Users/ogrisel/miniforge3/envs/dev/bin/python3.13
cachedir: .pytest_cache
rootdir: /Users/ogrisel/tmp
plugins: run-parallel-0.6.1.dev0, xdist-3.7.0, anyio-4.9.0
collected 1 item
Collected 0 items to run in parallel
test_with_tmp_path_fixture.py::test_with_tmp_path PASSED [100%]
================================================================== 1 passed in 0.09s ===================================================================
Note that it is now possible to configure pyproject.toml as follows:
[tool.pytest.ini_options]
thread_unsafe_fixtures = [
"tmp_path", # does not isolate temporary directories across threads.
]This configuration provides a low-maintenance solution to the first problem (maybe this should be the default?). However, as far as I know, there is no equivalent configuration to automatically mark those tests as repetition-unsafe.
Final note: there are other fixtures with the same problem, for instance tmpdir.