Skip to content

Commit

Permalink
pythongh-100131: Add optional delete parameter to tempfile.TemporaryD…
Browse files Browse the repository at this point in the history
…irectory() (python#100132)

Add optional delete parameter to tempfile.TemporaryDirectory().

Co-authored-by: Gregory P. Smith <greg@krypto.org>
  • Loading branch information
2 people authored and warsaw committed Apr 11, 2023
1 parent 719e599 commit b427155
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 8 deletions.
11 changes: 10 additions & 1 deletion Doc/library/tempfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ The module defines the following user-callable items:
or text *mode* was specified).


.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False)
.. class:: TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False, *, delete=True)

This class securely creates a temporary directory using the same rules as :func:`mkdtemp`.
The resulting object can be used as a context manager (see
Expand All @@ -195,13 +195,22 @@ The module defines the following user-callable items:
(the :func:`cleanup` call, exiting the context manager, when the object
is garbage-collected or during interpreter shutdown).

The *delete* parameter can be used to disable cleanup of the directory tree
upon exiting the context. While it may seem unusual for a context manager
to disable the action taken when exiting the context, it can be useful during
debugging or when you need your cleanup behavior to be conditional based on
other logic.

.. audit-event:: tempfile.mkdtemp fullpath tempfile.TemporaryDirectory

.. versionadded:: 3.2

.. versionchanged:: 3.10
Added *ignore_cleanup_errors* parameter.

.. versionchanged:: 3.12
Added the *delete* parameter.


.. function:: mkstemp(suffix=None, prefix=None, dir=None, text=False)

Expand Down
25 changes: 18 additions & 7 deletions Lib/tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -850,17 +850,26 @@ class TemporaryDirectory:
...
Upon exiting the context, the directory and everything contained
in it are removed.
in it are removed (unless delete=False is passed or an exception
is raised during cleanup and ignore_cleanup_errors is not True).
Optional Arguments:
suffix - A str suffix for the directory name. (see mkdtemp)
prefix - A str prefix for the directory name. (see mkdtemp)
dir - A directory to create this temp dir in. (see mkdtemp)
ignore_cleanup_errors - False; ignore exceptions during cleanup?
delete - True; whether the directory is automatically deleted.
"""

def __init__(self, suffix=None, prefix=None, dir=None,
ignore_cleanup_errors=False):
ignore_cleanup_errors=False, *, delete=True):
self.name = mkdtemp(suffix, prefix, dir)
self._ignore_cleanup_errors = ignore_cleanup_errors
self._delete = delete
self._finalizer = _weakref.finalize(
self, self._cleanup, self.name,
warn_message="Implicitly cleaning up {!r}".format(self),
ignore_errors=self._ignore_cleanup_errors)
ignore_errors=self._ignore_cleanup_errors, delete=self._delete)

@classmethod
def _rmtree(cls, name, ignore_errors=False):
Expand Down Expand Up @@ -894,9 +903,10 @@ def resetperms(path):
_shutil.rmtree(name, onexc=onexc)

@classmethod
def _cleanup(cls, name, warn_message, ignore_errors=False):
cls._rmtree(name, ignore_errors=ignore_errors)
_warnings.warn(warn_message, ResourceWarning)
def _cleanup(cls, name, warn_message, ignore_errors=False, delete=True):
if delete:
cls._rmtree(name, ignore_errors=ignore_errors)
_warnings.warn(warn_message, ResourceWarning)

def __repr__(self):
return "<{} {!r}>".format(self.__class__.__name__, self.name)
Expand All @@ -905,7 +915,8 @@ def __enter__(self):
return self.name

def __exit__(self, exc, value, tb):
self.cleanup()
if self._delete:
self.cleanup()

def cleanup(self):
if self._finalizer.detach() or _os.path.exists(self.name):
Expand Down
6 changes: 6 additions & 0 deletions Lib/test/test_tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import types
import weakref
import gc
import shutil
from unittest import mock

import unittest
Expand Down Expand Up @@ -1837,6 +1838,11 @@ def test_flags(self):
d.cleanup()
self.assertFalse(os.path.exists(d.name))

def test_delete_false(self):
with tempfile.TemporaryDirectory(delete=False) as working_dir:
pass
self.assertTrue(os.path.exists(working_dir))
shutil.rmtree(working_dir)

if __name__ == "__main__":
unittest.main()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`.

0 comments on commit b427155

Please sign in to comment.