Isolate and Debug File Side-Effects with Pytest tmp_path
One of the fixtures that Pytest offers is
tmp_path ↗
that it describes as having the following behavior:
"Return a temporary directory (as pathlib.Path object) which is unique to each
test function invocation."
It can be used to provide a unique, deterministic, isolated temporary directory for file operations a program needs to perform while being tested.
For example, my py-vmt CLI ↗ needs to
access and write files in the user's config and data dirs. Under test, I need
to monkeypatch that behavior to point to a tmp_path where the tests can
operate without clobbering one another or non-test uses of the CLI.
# auto fixture for all test cases that monkeypatches the platform dirs to a tmp
# path so that test side-effects don't persist between runs
@pytest.fixture(autouse=True)
def use_tmp_platform_dirs(tmp_path, monkeypatch):
data_dir = tmp_path / "data"
config_dir = tmp_path / "config"
data_dir.mkdir()
config_dir.mkdir()
monkeypatch.setattr(CliContext, "get_data_dir", staticmethod(lambda: data_dir))
monkeypatch.setattr(CliContext, "get_config_dir", staticmethod(lambda: config_dir))
What's particularly neat about this is that Pytest has a unique and
deterministic location for tmp_path for each run and unit test. It also has a
retention policy of 3, which means I can always go back and look at the state
of those directories for the last three runs of the test suite.
The docs ↗
describe the per-run and per-test directory structure of this tmp_path as:
{temproot}/pytest-of-{user}/pytest-{num}/{testname}/
where temproot can be found with tempfile.gettempdir().
>>> import tempfile
>>> tempfile.gettempdir()
'/var/folders/zc/q6gnvbgx6kq77828jn38716r0000gn/T'
Now that I have that directory location, I can start poking around at the rest of the path values. Eventually I drill down enough to access the data directory for one of those test cases.
❯ ls /var/folders/zc/q6gnvbgx6kq77828jn38716r0000gn/T/pytest-of-lastword/pytest-2
test_no_status0 test_start_at_past_timecurrent test_start_status_stop_flow0
test_no_statuscurrent test_start_cancel_flow0 test_start_status_stop_flowcurrent
test_start_at_past_time0 test_start_cancel_flowcurrent
❯ ls /var/folders/zc/q6gnvbgx6kq77828jn38716r0000gn/T/pytest-of-lastword/pytest-2/test_start_status_stop_flow0
config data
❯ cat /var/folders/zc/q6gnvbgx6kq77828jn38716r0000gn/T/pytest-of-lastword/pytest-2/test_start_status_stop_flow0/data/session_log.json
[{"end_time": "2026-03-14T16:35:11+00:00", "project_name": "my-project", "start_time": "2026-03-14T15:05:11+00:00"}]
This provides an additional place to look when debugging some unexpected behavior because I can peek at the final state of those files. Maybe there is a clue in there about what went wrong during a specific test failure.
If you want to see a full example of using tmp_path in this way, check out
this test_cli.py file for the py-vmt
repo ↗.