summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/tempfile.py26
-rw-r--r--Lib/test/test_tempfile.py9
-rw-r--r--Misc/NEWS.d/next/Library/2024-11-11-07-56-03.gh-issue-126639.AmVSt-.rst1
3 files changed, 30 insertions, 6 deletions
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index b5a15f7..0eb9dde 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -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
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 57e9bd2..7adc021 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -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
index 0000000..0b75e58
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-11-11-07-56-03.gh-issue-126639.AmVSt-.rst
@@ -0,0 +1 @@
+:class:`tempfile.NamedTemporaryFile` will now issue a :exc:`ResourceWarning` when it is finalized by the garbage collector without being explicitly closed.