Python Standard Library has a module to work with temporary files and directories: tempfile. This module handles creating the files/directories, naming them, and cleaning-up after done.

Precision Balance

To create a temporary directory: instantiate a tempfile.TemporaryDirectory object. By default, when this object is destroyed, the temporary directory created along with all its contents are wiped from disk. The name of the directory is saved in the name attribute. After the directory fulfills its duty, call the cleanup() method to remove the temporary bits. For example, to create a foo file in a temporary directory:

import tempfile

# Create temporary directory on disk
tmp_dir = tempfile.TemporaryDirectory()
print(tmp_dir.name) # Prints something like `/tmp/tmpr8d4aomi` on Unix

# Create a file in there with some content
with open(tmp_dir.name + "/foo", "w") as foo_file:
    foo_file.write("Temporary hello")

# Destroy dir and its contents
tmp_dir.cleanup()

tempfile.TemporaryDirectory can also be used as a context manager, to automatically cleanup the resources after we are done with them. One key difference is that, as a context manager, there’s no .name attribute. The snippet above can be rewritten to:

with tempfile.TemporaryDirectory() as tmp_dir:
    with open(tmp_dir + "/foo", "w") as foo_file:
        foo_file.write("Temporary hello")

The tempfile.TemporaryDirectory() constructor has some knobs to add a prefix or suffix to the directory name, specify a different base directory to use, and control whether to delete the directory when exiting the context (defaults to deleting).

In the examples above, we create a file in a temporary directory. But if all we want is a temporary file, we are better served with tempfile.TemporaryFile instead, which returns a file object. This file is deleted after closing:

tmp_file = tempfile.TemporaryFile()
tmp_file.write(b"Temporary hello")
tmp_file.close()

One interesting thing about this tempfile.TemporaryFile object is that it is kind of a ghost on Unixes: the file exists, but has no readable path, only a file descriptor. The documentation says (as of Python 3.13): Under Unix, the directory entry for the file is either not created at all or is removed immediately after the file is created. Pretty weird, in my opinion, but also cool.

If you need a file with a name, use tempfile.NamedTemporaryFile() instead. This way you get a file that has a visible name on disk, accessible via the name attribute. This named file is created under the tempfile.gettmpdir() directory.

tempfile.TemporaryFile and tempfile.NamedTemporaryFile can also be used as context managers, similar to tempfile.TemporaryDirectory:

with tempfile.NamedTemporaryFile() as tmp_file:
    tmp_file.write(b"Temporary hello")

In case you need temporary files in a test, don’t use tempfile module directly. Pytest provides the tmp_path fixture for temporary directories. This fixture is a pathlib.Path object pointing to an existing directory, unique to the test invocation.

Both pytest’s tmp_path and tempfile.TemporaryDirectory directories are created with 700 permission, that is, only the user that owns the Python process can read, write, and execute it, group and others have zero permissions (rwx------). Directories created via pathlib.Path.mkdir have 755, so group and others can read and execute (rwxr-xr-x). Files created with open() directly have 644 permission (rw-r--r--), while tempfile.TemporaryFile have 600 permission.

These differences in permissions can bite hard. If you need to change the permission, I suggest to create a pathlib.Path for the directory or file and then chmod it:

import tempfile
from pathlib import Path

with tempfile.TemporaryDirectory() as tmp_dir:
    tmp_path = Path(tmp_dir)
    tmp_path.chmod(0o755)
    foo(tmp_path)

You could also use the chmod function from the os module, but I’m a huge fan of pathlib and prefer it instead.