Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import struct
import sys
import time
import warnings # must stay eager to support finalization
import weakref
import zlib
from compression._common import _streams
Expand Down Expand Up @@ -229,7 +230,6 @@ def __init__(self, filename=None, mode=None,

elif mode.startswith(('w', 'a', 'x')):
if origmode is None:
import warnings
warnings.warn(
"GzipFile was opened for writing, but this will "
"change in future Python releases. "
Expand Down Expand Up @@ -466,13 +466,15 @@ def readline(self, size=-1):
self._check_not_closed()
return self._buffer.readline(size)

def __del__(self):
if self.mode == WRITE and not self.closed:
import warnings
warnings.warn("unclosed GzipFile",
ResourceWarning, source=self, stacklevel=2)

super().__del__()
def __del__(self, _warn=warnings.warn):
try:
# Wrap within a try to ensure the file is closed even if the
# warning raises, e.g. when ResourceWarning is made an error.
if self.mode == WRITE and not self.closed:
_warn("unclosed GzipFile",
ResourceWarning, source=self, stacklevel=2)
finally:
super().__del__()

def _read_exact(fp, n):
'''Read exactly *n* bytes from `fp`
Expand Down
16 changes: 15 additions & 1 deletion Lib/test/test_gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@
import struct
import sys
import unittest
import warnings
from subprocess import PIPE, Popen
from unittest import mock
from test.support import catch_unraisable_exception
from test.support import catch_unraisable_exception, gc_collect
from test.support import force_not_colorized_test_class, import_helper
from test.support import os_helper
from test.support import _4G, bigmemtest, requires_subprocess
Expand Down Expand Up @@ -965,6 +966,19 @@ def test_refloop_unraisable(self):
gc.collect()
self.assertIsNone(cm.unraisable)

def test_del_closes_if_warning_fails(self):
# ResourceWarning escalated to an error is reported as unraisable,
# and the file is still closed.
b = io.BytesIO()
f = gzip.GzipFile(fileobj=b, mode="wb")
f.write(data1)
with (warnings.catch_warnings(action="error", category=ResourceWarning),
catch_unraisable_exception() as cm):
del f
gc_collect()
self.assertIs(cm.unraisable.exc_type, ResourceWarning)
self.assertEqual(gzip.decompress(b.getvalue()), data1)


class TestOpen(BaseTest):
def test_binary_modes(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Fix :class:`gzip.GzipFile` not being closed at interpreter shutdown when
emitting its :exc:`ResourceWarning` failed with an :exc:`ImportError`.
Loading