Skip to content

Commit

Permalink
gh-126639: Add ResourceWarning to NamedTemporaryFile (#126677)
Browse files Browse the repository at this point in the history
Co-authored-by: Kumar Aditya <[email protected]>
  • Loading branch information
graingert and kumaraditya303 authored Dec 18, 2024
1 parent 2610bcc commit bad3cde
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 6 deletions.
26 changes: 23 additions & 3 deletions Lib/tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -469,7 +477,10 @@ def close(self):
self.cleanup()

def __del__(self):
close_called = self.close_called
self.cleanup()
if not close_called:
_warnings.warn(self.warn_message, ResourceWarning)


class _TemporaryFileWrapper:
Expand All @@ -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
Expand Down
9 changes: 6 additions & 3 deletions Lib/test/test_tempfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -1112,11 +1112,14 @@ def my_func(dir):
# 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 ")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:class:`tempfile.NamedTemporaryFile` will now issue a :exc:`ResourceWarning` when it is finalized by the garbage collector without being explicitly closed.

0 comments on commit bad3cde

Please sign in to comment.