I am using a Pytest fixture to clean up temporary files and directories created during tests. The fixture works for most test cases, but it fails to completely delete directories created in the first two parameterized tests. Here's the simplified fixture:
import pytest
import os
import shutil
@pytest.fixture(scope="session")
def cleanup_environment():
temp_paths = [] # List to track temporary paths
yield temp_paths # Provide the list to tests
# Sort paths by directory depth (deepest first)
temp_paths_sorted = sorted(temp_paths, key=lambda p: p.count(os.sep), reverse=True)
for temp_path in temp_paths_sorted:
if os.path.exists(temp_path):
try:
if os.path.isfile(temp_path):
os.remove(temp_path)
elif os.path.isdir(temp_path):
shutil.rmtree(temp_path, ignore_errors=True)
except Exception as e:
print(f"Failed to remove {temp_path}: {e}")
for temp_path in temp_paths_sorted:
parent_dir = os.path.dirname(temp_path)
while parent_dir and os.path.exists(parent_dir) and not os.listdir(parent_dir):
try:
os.rmdir(parent_dir)
parent_dir = os.path.dirname(parent_dir)
except Exception as e:
print(f"Failed to remove parent directory {parent_dir}: {e}")
break
Here are the test cases:
def test_create_and_delete_file(cleanup_environment, tmpdir):
temp_file = tmpdir.join("temp_file.txt")
temp_file.write("Temporary content")
cleanup_environment.append(str(temp_file))
assert temp_file.check(file=True)
def test_create_and_delete_dir(cleanup_environment, tmpdir):
temp_dir = tmpdir.mkdir("temp_dir")
cleanup_environment.append(str(temp_dir))
assert temp_dir.check(dir=True)
@pytest.mark.parametrize("test_case", ["case1", "case2"])
def test_parameterized_cases(cleanup_environment, tmpdir, test_case):
temp_dir = tmpdir.mkdir(f"temp_dir_{test_case}")
cleanup_environment.append(str(temp_dir))
assert temp_dir.check(dir=True)
In the parameterized test cases (case1
and case2
), the directories created are not fully deleted, even though they are appended to cleanup_environment
.
How can I ensure that all directories, including those from parameterized tests, are cleaned up properly?
Why are you bothering to track individual files and/or directories like this? It would make more sense to create a temporary directory per session, and then remove it entirely when you're done. This is easy if you use your own fixture to create temporary directories, rather than the pytest tmpdir
fixture (which is explicitly designed to not clean up after your tests, so that you can inspect test artifacts after the test run is complete).
Something like this:
import pytest
import tempfile
from pathlib import Path
@pytest.fixture(scope="session")
def clean_tmpdir():
# a tempfile.TemporaryDirectory() object deletes itself when it
# goes out of scope.
with tempfile.TemporaryDirectory() as tmpdir:
yield Path(tmpdir)
@pytest.mark.parametrize("test_case", ["case1", "case2"])
def test_parameterized_cases(clean_tmpdir: Path, test_case: str):
print(f"using directory: {clean_tmpdir}")
dir = clean_tmpdir / f"temp_dir_{test_case}"
dir.mkdir()
assert dir.is_dir()