Skip to content

Commit 48693fb

Browse files
committed
Import warnings eagerly in zipfile and simplify the tests
1 parent 9c41b95 commit 48693fb

3 files changed

Lines changed: 14 additions & 32 deletions

File tree

‎Lib/test/test_zipfile/test_core.py‎

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4095,28 +4095,13 @@ def test_garbage_collection(self):
40954095
zf.close()
40964096
del zf
40974097

4098-
def test_garbage_collection_closes_when_warning_fails(self):
4099-
buf = io.BytesIO()
4100-
zf = zipfile.ZipFile(buf, "w")
4101-
zf.writestr("f.txt", b"data")
4102-
with warnings.catch_warnings(), catch_unraisable_exception() as cm:
4103-
warnings.simplefilter("error", ResourceWarning)
4098+
# ResourceWarning escalated to an error is reported as unraisable.
4099+
zf = zipfile.ZipFile(io.BytesIO(), "w")
4100+
with (warnings.catch_warnings(action="error", category=ResourceWarning),
4101+
catch_unraisable_exception() as cm):
41044102
del zf
41054103
gc_collect()
4106-
self.assertIsInstance(cm.unraisable.exc_value, ResourceWarning)
4107-
with zipfile.ZipFile(buf) as zf:
4108-
self.assertEqual(zf.namelist(), ["f.txt"])
4109-
4110-
@requires_subprocess()
4111-
def test_unclosed_at_shutdown(self):
4112-
self.addCleanup(unlink, TESTFN)
4113-
script_helper.assert_python_ok("-c", f"""if 1:
4114-
import zipfile
4115-
zf = zipfile.ZipFile({TESTFN!r}, "w")
4116-
zf.writestr("f.txt", b"data")
4117-
""")
4118-
with zipfile.ZipFile(TESTFN) as zf:
4119-
self.assertEqual(zf.namelist(), ["f.txt"])
4104+
self.assertIs(cm.unraisable.exc_type, ResourceWarning)
41204105

41214106
def test_unsupported_version(self):
41224107
# File has an extract_version of 120

‎Lib/zipfile/__init__.py‎

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import sys
1313
import threading
1414
import time
15-
lazy import warnings
15+
import warnings # must stay eager to support finalization
1616

1717
try:
1818
import zlib # We may need its compression method
@@ -2650,14 +2650,10 @@ def __del__(self):
26502650
"""Call the "close()" method in case the user forgot."""
26512651
# gh-81954: Warn if writable ZipFile is implicitly closed.
26522652
# GC cleanup order is non-deterministic and can result in data loss.
2653-
try:
2654-
# Wrap within a try to ensure the file is closed even if the
2655-
# warnings module is unable to load during finalization.
2656-
if self.fp is not None and self.mode in ('w', 'x', 'a'):
2657-
warnings.warn(f"unclosed ZipFile {self!r}",
2658-
ResourceWarning, source=self, stacklevel=2)
2659-
finally:
2660-
self.close()
2653+
if self.fp is not None and self.mode in ('w', 'x', 'a'):
2654+
warnings.warn(f"unclosed ZipFile {self!r}",
2655+
ResourceWarning, source=self, stacklevel=2)
2656+
self.close()
26612657

26622658
def close(self):
26632659
"""Close the file, and for mode 'w', 'x' and 'a' write the ending
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
Fix data loss when a writable :class:`zipfile.ZipFile` that was never closed
2-
is finalized during interpreter shutdown: :meth:`~zipfile.ZipFile.close` is
3-
now called even if emitting the :exc:`ResourceWarning` fails.
1+
:mod:`zipfile` now imports :mod:`warnings` eagerly so that a writable
2+
:class:`~zipfile.ZipFile` left unclosed at interpreter shutdown can emit its
3+
:exc:`ResourceWarning` and be closed instead of failing with an
4+
:exc:`ImportError`.

0 commit comments

Comments
 (0)