]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-126639: Add ResourceWarning to NamedTemporaryFile (#126677)
authorThomas Grainger <tagrain@gmail.com>
Wed, 18 Dec 2024 10:12:24 +0000 (10:12 +0000)
committerGitHub <noreply@github.com>
Wed, 18 Dec 2024 10:12:24 +0000 (10:12 +0000)
Co-authored-by: Kumar Aditya <kumaraditya@python.org>
Lib/tempfile.py
Lib/test/test_tempfile.py
Misc/NEWS.d/next/Library/2024-11-11-07-56-03.gh-issue-126639.AmVSt-.rst [new file with mode: 0644]

index b5a15f7b72c872284b486360ab03feb17325e328..0eb9ddeb6ac377e5ad61d88faf2bbc4e59faecb2 100644 (file)
@@ -437,11 +437,19 @@ class _TemporaryFileCloser:
     cleanup_called = False
     close_called = False
 
-    def __init__(self, file, name, delete=True, delete_on_close=True):
+    def __init__(
+        self,
+        file,
+        name,
+        delete=True,
+        delete_on_close=True,
+        warn_message="Implicitly cleaning up unknown file",
+    ):
         self.file = file
         self.name = name
         self.delete = delete
         self.delete_on_close = delete_on_close
+        self.warn_message = warn_message
 
     def cleanup(self, windows=(_os.name == 'nt'), unlink=_os.unlink):
         if not self.cleanup_called:
@@ -469,7 +477,10 @@ class _TemporaryFileCloser:
                     self.cleanup()
 
     def __del__(self):
+        close_called = self.close_called
         self.cleanup()
+        if not close_called:
+            _warnings.warn(self.warn_message, ResourceWarning)
 
 
 class _TemporaryFileWrapper:
@@ -483,8 +494,17 @@ class _TemporaryFileWrapper:
     def __init__(self, file, name, delete=True, delete_on_close=True):
         self.file = file
         self.name = name
-        self._closer = _TemporaryFileCloser(file, name, delete,
-                                            delete_on_close)
+        self._closer = _TemporaryFileCloser(
+            file,
+            name,
+            delete,
+            delete_on_close,
+            warn_message=f"Implicitly cleaning up {self!r}",
+        )
+
+    def __repr__(self):
+        file = self.__dict__['file']
+        return f"<{type(self).__name__} {file=}>"
 
     def __getattr__(self, name):
         # Attribute lookups are delegated to the underlying file
index 57e9bd20c77ee1a5aaace40d613a0d69a3c922b3..7adc021d2982544c1f30e354d153b538e42a9bf2 100644 (file)
@@ -1112,11 +1112,14 @@ class TestNamedTemporaryFile(BaseTestCase):
             # Testing extreme case, where the file is not explicitly closed
             # f.close()
             return tmp_name
-        # Make sure that the garbage collector has finalized the file object.
-        gc.collect()
         dir = tempfile.mkdtemp()
         try:
-            tmp_name = my_func(dir)
+            with self.assertWarnsRegex(
+                expected_warning=ResourceWarning,
+                expected_regex=r"Implicitly cleaning up <_TemporaryFileWrapper file=.*>",
+            ):
+                tmp_name = my_func(dir)
+                support.gc_collect()
             self.assertFalse(os.path.exists(tmp_name),
                         f"NamedTemporaryFile {tmp_name!r} "
                         f"exists after finalizer ")
diff --git a/Misc/NEWS.d/next/Library/2024-11-11-07-56-03.gh-issue-126639.AmVSt-.rst b/Misc/NEWS.d/next/Library/2024-11-11-07-56-03.gh-issue-126639.AmVSt-.rst
new file mode 100644 (file)
index 0000000..0b75e58
--- /dev/null
@@ -0,0 +1 @@
+:class:`tempfile.NamedTemporaryFile` will now issue a :exc:`ResourceWarning` when it is finalized by the garbage collector without being explicitly closed.