gh-100131: Add optional delete parameter to tempfile.TemporaryDirectory() (#100132)

Add optional delete parameter to tempfile.TemporaryDirectory().

Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
JakobDev 2023-03-24 22:52:06 +01:00 committed by GitHub
parent ded9a7fc19
commit 64cb1a4f0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 35 additions and 8 deletions

View File

@ -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
@ -195,6 +195,12 @@ 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
@ -202,6 +208,9 @@ The module defines the following user-callable items:
.. 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)

View File

@ -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):
@ -894,9 +903,10 @@ class TemporaryDirectory:
_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)
@ -905,7 +915,8 @@ class TemporaryDirectory:
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):

View File

@ -12,6 +12,7 @@ import stat
import types
import weakref
import gc
import shutil
from unittest import mock
import unittest
@ -1837,6 +1838,11 @@ class TestTemporaryDirectory(BaseTestCase):
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()

View File

@ -0,0 +1 @@
Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`.