From e15d6f6f4150fbedeea3b26e0ecda13accfe03fe Mon Sep 17 00:00:00 2001 From: JakobDev Date: Fri, 9 Dec 2022 12:16:56 +0100 Subject: [PATCH 1/8] Add optional delete parameter to tempfile.TemporaryDirectory() --- Lib/tempfile.py | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index bb18d60db0d919..8ad1534d4816ac 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -854,13 +854,14 @@ class TemporaryDirectory: """ 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 +895,10 @@ def resetperms(path): _shutil.rmtree(name, onerror=onerror) @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 +907,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): From 31a496602e96f2740778702ea873cd50d4c1dfc0 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 9 Dec 2022 11:21:39 +0000 Subject: [PATCH 2/8] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst diff --git a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst new file mode 100644 index 00000000000000..45dbe6e9eee151 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst @@ -0,0 +1 @@ +Add optional delete parameter to tempfile.TemporaryDirectory() From f5e44b798c205926ebe02d4c57267e4117adc151 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 20 Mar 2023 11:15:27 +0100 Subject: [PATCH 3/8] Add test and documentation --- Lib/tempfile.py | 3 +++ Lib/test/test_tempfile.py | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 8ad1534d4816ac..5db2231ada8e15 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -851,6 +851,9 @@ class TemporaryDirectory: Upon exiting the context, the directory and everything contained in it are removed. + + Arguments: + 'delete' -- whether the directory is automatically deleted (default True). """ def __init__(self, suffix=None, prefix=None, dir=None, diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index 7c2c8de7a2e6fc..be95be9f1444a4 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -1837,6 +1837,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() From 266385b29636a4038add1417cae5efff7baf6e63 Mon Sep 17 00:00:00 2001 From: JakobDev Date: Mon, 20 Mar 2023 11:18:39 +0100 Subject: [PATCH 4/8] Add missing shutil import --- Lib/test/test_tempfile.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py index be95be9f1444a4..90155487cff585 100644 --- a/Lib/test/test_tempfile.py +++ b/Lib/test/test_tempfile.py @@ -12,6 +12,7 @@ import types import weakref import gc +import shutil from unittest import mock import unittest From 29b8c4ea232a208b8064bd9dc70c28d7e1e27277 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 24 Mar 2023 12:52:53 -0700 Subject: [PATCH 5/8] improve docstring, delete is keyword only. --- Lib/tempfile.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Lib/tempfile.py b/Lib/tempfile.py index 5db2231ada8e15..effaaced9ed2be 100644 --- a/Lib/tempfile.py +++ b/Lib/tempfile.py @@ -850,14 +850,19 @@ class TemporaryDirectory: ... Upon exiting the context, the directory and everything contained - in it are removed. - - Arguments: - 'delete' -- whether the directory is automatically deleted (default True). + 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, delete=True): + ignore_cleanup_errors=False, *, delete=True): self.name = mkdtemp(suffix, prefix, dir) self._ignore_cleanup_errors = ignore_cleanup_errors self._delete = delete From f887516e3da9c7b9db46765d862312da117e5f6d Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 24 Mar 2023 13:02:04 -0700 Subject: [PATCH 6/8] Document the change. --- Doc/library/tempfile.rst | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index b6d4f5dd05bbfc..e12d364aa95cc1 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -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,12 +195,21 @@ 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) From cf70ba4b07157e08c9b1e910b200b65ada292dde Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 24 Mar 2023 13:43:28 -0700 Subject: [PATCH 7/8] trailing whitespace from github.dev? it's more likely than you think. --- Doc/library/tempfile.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst index e12d364aa95cc1..61358eb76925b2 100644 --- a/Doc/library/tempfile.rst +++ b/Doc/library/tempfile.rst @@ -207,7 +207,7 @@ The module defines the following user-callable items: .. versionchanged:: 3.10 Added *ignore_cleanup_errors* parameter. - + .. versionchanged:: 3.12 Added the *delete* parameter. From 92ac7ba794271f9437993b859799dc6f4355b1f8 Mon Sep 17 00:00:00 2001 From: "Gregory P. Smith" Date: Fri, 24 Mar 2023 13:56:08 -0700 Subject: [PATCH 8/8] ReSTify the NEWS entry. --- .../next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst index 45dbe6e9eee151..07891f2c1e9eb6 100644 --- a/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst +++ b/Misc/NEWS.d/next/Library/2022-12-09-11-21-38.gh-issue-100131.v863yR.rst @@ -1 +1 @@ -Add optional delete parameter to tempfile.TemporaryDirectory() +Added an optional ``delete`` keyword argument to :class:`tempfile.TemporaryDirectory`.