Skip to content

Commit 95d06b9

Browse files
committed
Fix bug where write_gzip_header was used incorrectly
1 parent 44fa4ef commit 95d06b9

File tree

2 files changed

+26
-15
lines changed

2 files changed

+26
-15
lines changed

src/isal/igzip.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,18 +159,27 @@ def flush(self, zlib_mode=isal_zlib.Z_SYNC_FLUSH):
159159
super().flush(zlib_mode)
160160

161161
def _write_gzip_header(self, compresslevel=_COMPRESS_LEVEL_TRADEOFF):
162-
# Determine what xfl flag is written for the compression level.
163-
# Equate the fast level to gzip level 1. All the other levels are
164-
# medium.
165-
if sys.version_info[0] == 3 and sys.version_info[1] < 7:
166-
# Correct header introduced in 3.7
167-
super()._write_gzip_header()
168-
else:
162+
# Python 3.9 added a `compresslevel` parameter to write gzip header.
163+
# This only determines the value of one extra flag. Because this change
164+
# was backported to 3.7 and 3.8 in later point versions, the attributes
165+
# of the function should be checked before trying to use the
166+
# compresslevel parameter.
167+
# The gzip header has an extra flag that can be set depending on the
168+
# compression level used. This should be set when either the fastest or
169+
# best method is used. ISAL level 0 is larger than gzip level 1 and
170+
# much faster, so setting the flag for fastest level is appropriate.
171+
# ISAL level 1,2 and 3 (best)are similar in size and fall around the
172+
# gzip level 3 size. So setting no extra flag
173+
# (by using COMPRESS_LEVEL_TRADEOFF) is appropriate here.
174+
if ("compresslevel" in super()._write_gzip_header.__code__.co_varnames
175+
and hasattr(gzip, "_COMPRESS_LEVEL_FAST")
176+
and hasattr(gzip, "_COMPRESS_LEVEL_TRADEOFF")):
169177
if compresslevel == _COMPRESS_LEVEL_FAST:
170-
compresslevel = gzip._COMPRESS_LEVEL_FAST
178+
super()._write_gzip_header(gzip._COMPRESS_LEVEL_FAST)
171179
else:
172-
compresslevel = gzip._COMPRESS_LEVEL_TRADEOFF
173-
super()._write_gzip_header(compresslevel)
180+
super()._write_gzip_header(gzip._COMPRESS_LEVEL_TRADEOFF)
181+
else:
182+
super()._write_gzip_header()
174183

175184
def write(self, data):
176185
self._check_not_closed()

tests/test_gzip_compliance.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,11 @@ def test_metadata(self):
365365
struct.pack('<i', mtime)) # little-endian
366366

367367
xflByte = fRead.read(1)
368-
if sys.version_info[0] == 3 and sys.version_info[1] < 7:
369-
self.assertEqual(xflByte, b'\x02') # maximum compression
368+
if ("compresslevel" in
369+
gzip.GzipFile._write_gzip_header.__code__.co_varnames):
370+
self.assertEqual(xflByte, b'\x00') # fast compression
370371
else:
371-
self.assertEqual(xflByte, b'\x00') # medium compression
372+
self.assertEqual(xflByte, b'\x02') # maximum compression
372373
osByte = fRead.read(1)
373374
self.assertEqual(osByte, b'\xff') # OS "unknown" (OS-independent)
374375

@@ -399,8 +400,9 @@ def test_compresslevel_metadata(self):
399400
# specifically, discussion of XFL in section 2.3.1
400401
cases = [
401402
('fast', 0, b'\x04'),
402-
('best', 3, b'\x00'), # Comparable to medium gzip level.
403-
('tradeoff', 2, b'\x00'), # Dito
403+
('best', 3, b'\x00'), # Smaller than fast, bigger than best gzip.
404+
('tradeoff', 2, b'\x00'), # therefore medium is appropriate.
405+
('1', 1, b'\x00')
404406
]
405407
xflOffset = 8
406408

0 commit comments

Comments
 (0)