Skip to content

Commit

Permalink
[3.12] GH-105808: Fix a regression introduced in GH-101251 (GH-105910) (
Browse files Browse the repository at this point in the history
#105920)

GH-105808: Fix a regression introduced in GH-101251 (GH-105910)

Fix a regression introduced in GH-101251, causing GzipFile.flush() to
not flush the compressor (nor pass along the zip_mode argument).
(cherry picked from commit 1858db7)

Co-authored-by: T. Wouters <thomas@python.org>
  • Loading branch information
miss-islington and Yhg1s committed Jun 19, 2023
1 parent 5e524ef commit 225cc4c
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 1 deletion.
3 changes: 2 additions & 1 deletion Lib/gzip.py
Expand Up @@ -370,8 +370,9 @@ def close(self):
def flush(self,zlib_mode=zlib.Z_SYNC_FLUSH):
self._check_not_closed()
if self.mode == WRITE:
# Ensure the compressor's buffer is flushed
self._buffer.flush()
# Ensure the compressor's buffer is flushed
self.fileobj.write(self.compress.flush(zlib_mode))
self.fileobj.flush()

def fileno(self):
Expand Down
49 changes: 49 additions & 0 deletions Lib/test/test_gzip.py
Expand Up @@ -9,6 +9,7 @@
import struct
import sys
import unittest
import zlib
from subprocess import PIPE, Popen
from test.support import import_helper
from test.support import os_helper
Expand Down Expand Up @@ -616,6 +617,54 @@ def test_issue44439(self):
self.assertEqual(f.write(q), LENGTH)
self.assertEqual(f.tell(), LENGTH)

def test_flush_flushes_compressor(self):
# See issue GH-105808.
b = io.BytesIO()
message = b"important message here."
with gzip.GzipFile(fileobj=b, mode='w') as f:
f.write(message)
f.flush()
partial_data = b.getvalue()
full_data = b.getvalue()
self.assertEqual(gzip.decompress(full_data), message)
# The partial data should contain the gzip header and the complete
# message, but not the end-of-stream markers (so we can't just
# decompress it directly).
with self.assertRaises(EOFError):
gzip.decompress(partial_data)
d = zlib.decompressobj(wbits=-zlib.MAX_WBITS)
f = io.BytesIO(partial_data)
gzip._read_gzip_header(f)
read_message = d.decompress(f.read())
self.assertEqual(read_message, message)

def test_flush_modes(self):
# Make sure the argument to flush is properly passed to the
# zlib.compressobj; see issue GH-105808.
class FakeCompressor:
def __init__(self):
self.modes = []
def compress(self, data):
return b''
def flush(self, mode=-1):
self.modes.append(mode)
return b''
b = io.BytesIO()
fc = FakeCompressor()
with gzip.GzipFile(fileobj=b, mode='w') as f:
f.compress = fc
f.flush()
f.flush(50)
f.flush(zlib_mode=100)
# The implicit close will also flush the compressor.
expected_modes = [
zlib.Z_SYNC_FLUSH,
50,
100,
-1,
]
self.assertEqual(fc.modes, expected_modes)


class TestOpen(BaseTest):
def test_binary_modes(self):
Expand Down
@@ -0,0 +1 @@
Fix a regression introduced in GH-101251 for 3.12, causing :meth:`gzip.GzipFile.flush` to not flush the compressor (nor pass along the ``zip_mode`` argument).

0 comments on commit 225cc4c

Please sign in to comment.