Source code for zensols.util.tempfile

"""Classes to generate, track and clean up temporary files.

"""
from __future__ import annotations
__author__ = 'Paul Landes'
from typing import Tuple, List
import logging
from pathlib import Path
import tempfile as tf

logger = logging.getLogger(__name__)


[docs] class TemporaryFileName(object): """Create a temporary file names on the file system. Note that this does not create the file object itself, only the file names. In addition, the generated file names are tracked and allow for deletion. Specified directories are also created, which is only needed for non-system temporary directories. The object is iterable, so usage with ``itertools.islice`` can be used to get as many temporary file names as desired. Calling instances (no arguments) generate a single file name. """
[docs] def __init__(self, directory: str = None, file_fmt: str = '{name}', create: bool = False, remove: bool = True): """Initialize with file system data. :param directory: the parent directory of the generated file :param file_fmt: a file format that substitutes ``name`` for the create temporary file name; defaults to ``{name}`` :param create: if ``True``, create ``directory`` if it doesn't exist :param remove: if ``True``, remove tracked generated file names if they exist :see tempfile: """ if directory is None: self._directory = Path(tf._get_default_tempdir()) else: self._directory = Path(directory) self._file_fmt = file_fmt self._create = create self._remove = remove self._created: List[Path] = []
@property def files(self) -> Tuple[Path, ...]: """Return the file that have been created thus far.""" return tuple(self._created) def __iter__(self) -> TemporaryFileName: return self def _format_name(self, fname: str) -> str: return self._file_fmt.format(name=fname, index=len(self)) def __next__(self) -> Path: fname = next(tf._get_candidate_names()) fname = self._format_name(fname) if self._create and not self._directory.exists(): if logger.isEnabledFor(logging.INFO): logger.info(f'creating directory {self._directory}') self._directory.mkdir(parents=True, exist_ok=True) path = Path(self._directory, fname) self._created.append(path) return path def __call__(self) -> Path: return next(self) def __len__(self) -> int: return len(self._created)
[docs] def clean(self): """Remove any files generated from this instance. Note this only deletes the files, not the parent directory (if it was created). This does nothing if ``remove`` is ``False`` in the initializer. """ if self._remove: for path in self._created: logger.debug(f'delete candidate: {path}') if path.exists(): logger.info(f'removing temorary file {path}') path.unlink()
[docs] class tempfile(object): """Generate a temporary file name and return the name in the ``with`` statement. Arguments to the form are the same as ``TemporaryFileName``. The temporary file is deleted after completion (see ``TemporaryFileName``). Example: .. code-block:: python with tempfile('./tmp', create=True) as fname: print(f'writing to {fname}') with open(fname, 'w') as f: f.write('this file will be deleted, but left with ./tmp\\n') """
[docs] def __init__(self, *args, **kwargs): self.temp = TemporaryFileName(*args, **kwargs)
def __enter__(self): self.path = self.temp() return self.path def __exit__(self, type, value, traceback): self.temp.clean()