Skip to content

c108.scratch

Utilities for creating and managing temporary directories with customizable names

Provides temp_dir(), a context manager for secure temporary directories with timestamp/PID/randomized naming.

temp_dir(*, parent=None, name_format='tmp-{random}', delete=True, ignore_cleanup_errors=False)

Context manager that provides a Path object to a temporary directory.

The directory is created when entering the context and automatically removed (along with its contents) when exiting, unless delete=False.

Parameters:

Name Type Description Default
parent str | PathLike[str] | None

Optional parent directory where temp dir will be created. If None, uses the system default temp directory.

None
name_format str

Format string for directory name. Available placeholders: - {random}: Random characters for uniqueness (e.g., "x7k2p9qr") - {timestamp}: UTC timestamp (e.g., "20250101-143010") - {timestamp:fmt}: Formatted UTC timestamp using strftime syntax in FMT, e.g. %Y%m%d - {pid}: Process ID

'tmp-{random}'
delete bool

If True (default), remove the directory on context exit.

True
ignore_cleanup_errors bool

If True, suppress errors during cleanup when delete=True.

False

Yields:

Name Type Description
Path Path

A pathlib.Path object pointing to the temporary directory.

Raises:

Type Description
OSError

From tempfile.TemporaryDirectory if directory creation fails.

PermissionError

From tempfile.TemporaryDirectory if lacking permissions.

ValueError

If name_format contains invalid placeholders or format syntax.

Examples:

Basic usage:

>>> with temp_dir() as tmp:
...     config_file = tmp / "config.json"
...     n_bytes = config_file.write_text('{"key": "value"}')
...     assert config_file.exists()

Timestamped directory:

>>> with temp_dir(name_format="build-{timestamp:%Y%m%d}-{random}") as tmp:
...     # Creates: /tmp/build-20251014-x7k2p9qr
...     pass

Process-specific directory:

>>> with temp_dir(name_format="worker-{pid}-{random}") as tmp:
...     # Creates: /tmp/worker-12345-x7k2p9qr
...     pass

Custom parent directory:

>>> with temp_dir(parent="/tmp") as tmp:
...     assert tmp.parent == Path("/tmp")

Preserve for debugging:

>>> with temp_dir(delete=False, name_format="debug-{timestamp}-{random}") as tmp:
...     debug_log = tmp / "debug.log"
...     n_bytes = debug_log.write_text("Debug info")
>>> assert debug_log.exists()
Note

The temporary directory is created in a secure manner with appropriate permissions (0o700 on Unix-like systems). Timestamps use UTC to ensure unambiguous, sortable filenames. The {random} placeholder ensures uniqueness even with identical timestamps or PIDs.

Source code in c108/scratch.py
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
@contextmanager
def temp_dir(
    *,
    parent: str | os.PathLike[str] | None = None,
    name_format: str = "tmp-{random}",
    delete: bool = True,
    ignore_cleanup_errors: bool = False,
) -> Iterator[Path]:
    """
    Context manager that provides a Path object to a temporary directory.

    The directory is created when entering the context and automatically removed
    (along with its contents) when exiting, unless delete=False.

    Args:
        parent: Optional parent directory where temp dir will be created.
            If None, uses the system default temp directory.
        name_format: Format string for directory name. Available placeholders:
            - {random}: Random characters for uniqueness (e.g., "x7k2p9qr")
            - {timestamp}: UTC timestamp (e.g., "20250101-143010")
            - {timestamp:fmt}: Formatted UTC timestamp using strftime syntax in FMT, e.g. ``%Y%m%d``
            - {pid}: Process ID
        delete: If True (default), remove the directory on context exit.
        ignore_cleanup_errors: If True, suppress errors during cleanup when delete=True.

    Yields:
        Path: A pathlib.Path object pointing to the temporary directory.

    Raises:
        OSError: From tempfile.TemporaryDirectory if directory creation fails.
        PermissionError: From tempfile.TemporaryDirectory if lacking permissions.
        ValueError: If name_format contains invalid placeholders or format syntax.

    Examples:
        Basic usage:
        >>> with temp_dir() as tmp:
        ...     config_file = tmp / "config.json"
        ...     n_bytes = config_file.write_text('{"key": "value"}')
        ...     assert config_file.exists()

        Timestamped directory:
        >>> with temp_dir(name_format="build-{timestamp:%Y%m%d}-{random}") as tmp:
        ...     # Creates: /tmp/build-20251014-x7k2p9qr
        ...     pass

        Process-specific directory:
        >>> with temp_dir(name_format="worker-{pid}-{random}") as tmp:
        ...     # Creates: /tmp/worker-12345-x7k2p9qr
        ...     pass

        Custom parent directory:
        >>> with temp_dir(parent="/tmp") as tmp:
        ...     assert tmp.parent == Path("/tmp")

        Preserve for debugging:
        >>> with temp_dir(delete=False, name_format="debug-{timestamp}-{random}") as tmp:
        ...     debug_log = tmp / "debug.log"
        ...     n_bytes = debug_log.write_text("Debug info")
        >>> assert debug_log.exists()

    Note:
        The temporary directory is created in a secure manner with appropriate
        permissions (0o700 on Unix-like systems). Timestamps use UTC to ensure
        unambiguous, sortable filenames. The {random} placeholder ensures
        uniqueness even with identical timestamps or PIDs.
    """
    # Parse the name_format to extract prefix and suffix around {random}
    prefix, suffix = _temp_dir_parse_name_fmt(name_format)

    # Create the temporary directory with parsed prefix/suffix
    with tempfile.TemporaryDirectory(
        prefix=prefix,
        suffix=suffix,
        dir=parent,
        delete=delete,
        ignore_cleanup_errors=ignore_cleanup_errors,
    ) as tmpdir_str:
        yield Path(tmpdir_str)