mirror of https://github.com/python/cpython
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:
parent
ded9a7fc19
commit
64cb1a4f0f
|
@ -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)
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`.
|
Loading…
Reference in New Issue