mirror of
https://github.com/python/cpython.git
synced 2025-08-04 17:08:35 +00:00
gh-58451: Add optional delete_on_close parameter to NamedTemporaryFile (GH-97015)
This commit is contained in:
parent
bbc7cd649a
commit
743453a554
5 changed files with 215 additions and 50 deletions
|
@ -11,6 +11,7 @@ import contextlib
|
|||
import stat
|
||||
import types
|
||||
import weakref
|
||||
import gc
|
||||
from unittest import mock
|
||||
|
||||
import unittest
|
||||
|
@ -1013,6 +1014,102 @@ class TestNamedTemporaryFile(BaseTestCase):
|
|||
pass
|
||||
self.assertRaises(ValueError, use_closed)
|
||||
|
||||
def test_context_man_not_del_on_close_if_delete_on_close_false(self):
|
||||
# Issue gh-58451: tempfile.NamedTemporaryFile is not particulary useful
|
||||
# on Windows
|
||||
# A NamedTemporaryFile is NOT deleted when closed if
|
||||
# delete_on_close=False, but is deleted on context manager exit
|
||||
dir = tempfile.mkdtemp()
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(dir=dir,
|
||||
delete=True,
|
||||
delete_on_close=False) as f:
|
||||
f.write(b'blat')
|
||||
f_name = f.name
|
||||
f.close()
|
||||
with self.subTest():
|
||||
# Testing that file is not deleted on close
|
||||
self.assertTrue(os.path.exists(f.name),
|
||||
f"NamedTemporaryFile {f.name!r} is incorrectly "
|
||||
f"deleted on closure when delete_on_close=False")
|
||||
|
||||
with self.subTest():
|
||||
# Testing that file is deleted on context manager exit
|
||||
self.assertFalse(os.path.exists(f.name),
|
||||
f"NamedTemporaryFile {f.name!r} exists "
|
||||
f"after context manager exit")
|
||||
|
||||
finally:
|
||||
os.rmdir(dir)
|
||||
|
||||
def test_context_man_ok_to_delete_manually(self):
|
||||
# In the case of delete=True, a NamedTemporaryFile can be manually
|
||||
# deleted in a with-statement context without causing an error.
|
||||
dir = tempfile.mkdtemp()
|
||||
try:
|
||||
with tempfile.NamedTemporaryFile(dir=dir,
|
||||
delete=True,
|
||||
delete_on_close=False) as f:
|
||||
f.write(b'blat')
|
||||
f.close()
|
||||
os.unlink(f.name)
|
||||
|
||||
finally:
|
||||
os.rmdir(dir)
|
||||
|
||||
def test_context_man_not_del_if_delete_false(self):
|
||||
# A NamedTemporaryFile is not deleted if delete = False
|
||||
dir = tempfile.mkdtemp()
|
||||
f_name = ""
|
||||
try:
|
||||
# Test that delete_on_close=True has no effect if delete=False.
|
||||
with tempfile.NamedTemporaryFile(dir=dir, delete=False,
|
||||
delete_on_close=True) as f:
|
||||
f.write(b'blat')
|
||||
f_name = f.name
|
||||
self.assertTrue(os.path.exists(f.name),
|
||||
f"NamedTemporaryFile {f.name!r} exists after close")
|
||||
finally:
|
||||
os.unlink(f_name)
|
||||
os.rmdir(dir)
|
||||
|
||||
def test_del_by_finalizer(self):
|
||||
# A NamedTemporaryFile is deleted when finalized in the case of
|
||||
# delete=True, delete_on_close=False, and no with-statement is used.
|
||||
def my_func(dir):
|
||||
f = tempfile.NamedTemporaryFile(dir=dir, delete=True,
|
||||
delete_on_close=False)
|
||||
tmp_name = f.name
|
||||
f.write(b'blat')
|
||||
# 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)
|
||||
self.assertFalse(os.path.exists(tmp_name),
|
||||
f"NamedTemporaryFile {tmp_name!r} "
|
||||
f"exists after finalizer ")
|
||||
finally:
|
||||
os.rmdir(dir)
|
||||
|
||||
def test_correct_finalizer_work_if_already_deleted(self):
|
||||
# There should be no error in the case of delete=True,
|
||||
# delete_on_close=False, no with-statement is used, and the file is
|
||||
# deleted manually.
|
||||
def my_func(dir)->str:
|
||||
f = tempfile.NamedTemporaryFile(dir=dir, delete=True,
|
||||
delete_on_close=False)
|
||||
tmp_name = f.name
|
||||
f.write(b'blat')
|
||||
f.close()
|
||||
os.unlink(tmp_name)
|
||||
return tmp_name
|
||||
# Make sure that the garbage collector has finalized the file object.
|
||||
gc.collect()
|
||||
|
||||
def test_bad_mode(self):
|
||||
dir = tempfile.mkdtemp()
|
||||
self.addCleanup(os_helper.rmtree, dir)
|
||||
|
@ -1081,7 +1178,8 @@ class TestSpooledTemporaryFile(BaseTestCase):
|
|||
missing_attrs = iobase_attrs - spooledtempfile_attrs
|
||||
self.assertFalse(
|
||||
missing_attrs,
|
||||
'SpooledTemporaryFile missing attributes from IOBase/BufferedIOBase/TextIOBase'
|
||||
'SpooledTemporaryFile missing attributes from '
|
||||
'IOBase/BufferedIOBase/TextIOBase'
|
||||
)
|
||||
|
||||
def test_del_on_close(self):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue