Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0fdf41d

Browse files
committed
Issue #5784: Expand documentation and tests for zlib wbits parameter
Based on documentation by AM Kuchling.
1 parent 0619878 commit 0fdf41d

4 files changed

Lines changed: 108 additions & 25 deletions

File tree

Doc/library/zlib.rst

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,22 @@ The available exception and functions in this module are:
6969
*method* is the compression algorithm. Currently, the only supported value is
7070
``DEFLATED``.
7171

72-
*wbits* is the base two logarithm of the size of the window buffer. This
73-
should be an integer from ``8`` to ``15``. Higher values give better
74-
compression, but use more memory.
72+
The *wbits* argument controls the size of the history buffer (or the
73+
"window size") used when compressing data, and whether a header and
74+
trailer is included in the output. It can take several ranges of values:
75+
76+
* +9 to +15: The base-two logarithm of the window size, which
77+
therefore ranges between 512 and 32768. Larger values produce
78+
better compression at the expense of greater memory usage. The
79+
resulting output will include a zlib-specific header and trailer.
80+
81+
* −9 to −15: Uses the absolute value of *wbits* as the
82+
window size logarithm, while producing a raw output stream with no
83+
header or trailing checksum.
84+
85+
* +25 to +31 = 16 + (9 to 15): Uses the low 4 bits of the value as the
86+
window size logarithm, while including a basic :program:`gzip` header
87+
and trailing checksum in the output.
7588

7689
The *memLevel* argument controls the amount of memory used for the
7790
internal compression state. Valid values range from ``1`` to ``9``.
@@ -113,20 +126,39 @@ The available exception and functions in this module are:
113126
.. function:: decompress(data[, wbits[, bufsize]])
114127

115128
Decompresses the bytes in *data*, returning a bytes object containing the
116-
uncompressed data. The *wbits* parameter controls the size of the window
117-
buffer, and is discussed further below.
129+
uncompressed data. The *wbits* parameter depends on
130+
the format of *data*, and is discussed further below.
118131
If *bufsize* is given, it is used as the initial size of the output
119132
buffer. Raises the :exc:`error` exception if any error occurs.
120133

121-
The absolute value of *wbits* is the base two logarithm of the size of the
122-
history buffer (the "window size") used when compressing data. Its absolute
123-
value should be between 8 and 15 for the most recent versions of the zlib
124-
library, larger values resulting in better compression at the expense of greater
125-
memory usage. When decompressing a stream, *wbits* must not be smaller
134+
.. _decompress-wbits:
135+
136+
The *wbits* parameter controls the size of the history buffer
137+
(or "window size"), and what header and trailer format is expected.
138+
It is similar to the parameter for :func:`compressobj`, but accepts
139+
more ranges of values:
140+
141+
* +8 to +15: The base-two logarithm of the window size. The input
142+
must include a zlib header and trailer.
143+
144+
* 0: Automatically determine the window size from the zlib header.
145+
146+
* −8 to −15: Uses the absolute value of *wbits* as the window size
147+
logarithm. The input must be a raw stream with no header or trailer.
148+
149+
* +24 to +31 = 16 + (8 to 15): Uses the low 4 bits of the value as
150+
the window size logarithm. The input must include a gzip header and
151+
trailer.
152+
153+
* +40 to +47 = 32 + (8 to 15): Uses the low 4 bits of the value as
154+
the window size logarithm, and automatically accepts either
155+
the zlib or gzip format.
156+
157+
When decompressing a stream, the window size must not be smaller
126158
than the size originally used to compress the stream; using a too-small
127-
value will result in an exception. The default value is therefore the
128-
highest value, 15. When *wbits* is negative, the standard
129-
:program:`gzip` header is suppressed.
159+
value may result in an :exc:`error` exception. The default *wbits* value
160+
is 15, which corresponds to the largest window size and requires a zlib
161+
header and trailer to be included.
130162

131163
*bufsize* is the initial size of the buffer used to hold decompressed data. If
132164
more space is required, the buffer size will be increased as needed, so you
@@ -139,7 +171,9 @@ The available exception and functions in this module are:
139171
Returns a decompression object, to be used for decompressing data streams that
140172
won't fit into memory at once.
141173

142-
The *wbits* parameter controls the size of the window buffer.
174+
The *wbits* parameter controls the size of the history buffer (or the
175+
"window size"), and what header and trailer format is expected. It has
176+
the same meaning as `described for decompress() <#decompress-wbits>`__.
143177

144178
The *zdict* parameter specifies a predefined compression dictionary. If
145179
provided, this must be the same dictionary as was used by the compressor that

Lib/test/test_zlib.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,49 @@ def test_length_overflow(self, size):
680680
finally:
681681
data = None
682682

683+
def test_wbits(self):
684+
co = zlib.compressobj(level=1, wbits=15)
685+
zlib15 = co.compress(HAMLET_SCENE) + co.flush()
686+
self.assertEqual(zlib.decompress(zlib15, 15), HAMLET_SCENE)
687+
self.assertEqual(zlib.decompress(zlib15, 0), HAMLET_SCENE)
688+
self.assertEqual(zlib.decompress(zlib15, 32 + 15), HAMLET_SCENE)
689+
with self.assertRaisesRegex(zlib.error, 'invalid window size'):
690+
zlib.decompress(zlib15, 14)
691+
dco = zlib.decompressobj(wbits=32 + 15)
692+
self.assertEqual(dco.decompress(zlib15), HAMLET_SCENE)
693+
dco = zlib.decompressobj(wbits=14)
694+
with self.assertRaisesRegex(zlib.error, 'invalid window size'):
695+
dco.decompress(zlib15)
696+
697+
co = zlib.compressobj(level=1, wbits=9)
698+
zlib9 = co.compress(HAMLET_SCENE) + co.flush()
699+
self.assertEqual(zlib.decompress(zlib9, 9), HAMLET_SCENE)
700+
self.assertEqual(zlib.decompress(zlib9, 15), HAMLET_SCENE)
701+
self.assertEqual(zlib.decompress(zlib9, 0), HAMLET_SCENE)
702+
self.assertEqual(zlib.decompress(zlib9, 32 + 9), HAMLET_SCENE)
703+
dco = zlib.decompressobj(wbits=32 + 9)
704+
self.assertEqual(dco.decompress(zlib9), HAMLET_SCENE)
705+
706+
co = zlib.compressobj(level=1, wbits=-15)
707+
deflate15 = co.compress(HAMLET_SCENE) + co.flush()
708+
self.assertEqual(zlib.decompress(deflate15, -15), HAMLET_SCENE)
709+
dco = zlib.decompressobj(wbits=-15)
710+
self.assertEqual(dco.decompress(deflate15), HAMLET_SCENE)
711+
712+
co = zlib.compressobj(level=1, wbits=-9)
713+
deflate9 = co.compress(HAMLET_SCENE) + co.flush()
714+
self.assertEqual(zlib.decompress(deflate9, -9), HAMLET_SCENE)
715+
self.assertEqual(zlib.decompress(deflate9, -15), HAMLET_SCENE)
716+
dco = zlib.decompressobj(wbits=-9)
717+
self.assertEqual(dco.decompress(deflate9), HAMLET_SCENE)
718+
719+
co = zlib.compressobj(level=1, wbits=16 + 15)
720+
gzip = co.compress(HAMLET_SCENE) + co.flush()
721+
self.assertEqual(zlib.decompress(gzip, 16 + 15), HAMLET_SCENE)
722+
self.assertEqual(zlib.decompress(gzip, 32 + 15), HAMLET_SCENE)
723+
dco = zlib.decompressobj(32 + 15)
724+
self.assertEqual(dco.decompress(gzip), HAMLET_SCENE)
725+
683726

684727
def genblock(seed, length, step=1024, generator=random):
685728
"""length-byte stream of random data from a seed (in step-byte blocks)."""

Modules/clinic/zlibmodule.c.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ PyDoc_STRVAR(zlib_decompress__doc__,
4848
" data\n"
4949
" Compressed data.\n"
5050
" wbits\n"
51-
" The window buffer size.\n"
51+
" The window buffer size and container format.\n"
5252
" bufsize\n"
5353
" The initial output buffer size.");
5454

@@ -95,7 +95,10 @@ PyDoc_STRVAR(zlib_compressobj__doc__,
9595
" method\n"
9696
" The compression algorithm. If given, this must be DEFLATED.\n"
9797
" wbits\n"
98-
" The base two logarithm of the window size (range: 8..15).\n"
98+
" +9 to +15: The base-two logarithm of the window size. Include a zlib\n"
99+
" container.\n"
100+
" -9 to -15: Generate a raw stream.\n"
101+
" +25 to +31: Include a gzip container.\n"
99102
" memLevel\n"
100103
" Controls the amount of memory used for internal compression state.\n"
101104
" Valid values range from 1 to 9. Higher values result in higher memory\n"
@@ -146,7 +149,7 @@ PyDoc_STRVAR(zlib_decompressobj__doc__,
146149
"Return a decompressor object.\n"
147150
"\n"
148151
" wbits\n"
149-
" The window buffer size.\n"
152+
" The window buffer size and container format.\n"
150153
" zdict\n"
151154
" The predefined compression dictionary. This must be the same\n"
152155
" dictionary as used by the compressor that produced the input data.");
@@ -439,4 +442,4 @@ zlib_crc32(PyModuleDef *module, PyObject *args)
439442
#ifndef ZLIB_COMPRESS_COPY_METHODDEF
440443
#define ZLIB_COMPRESS_COPY_METHODDEF
441444
#endif /* !defined(ZLIB_COMPRESS_COPY_METHODDEF) */
442-
/*[clinic end generated code: output=cf81e1deae3af0ce input=a9049054013a1b77]*/
445+
/*[clinic end generated code: output=f31627b314a7bd2f input=a9049054013a1b77]*/

Modules/zlibmodule.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ zlib.decompress
271271
data: Py_buffer
272272
Compressed data.
273273
wbits: int(c_default="MAX_WBITS") = MAX_WBITS
274-
The window buffer size.
274+
The window buffer size and container format.
275275
bufsize: capped_uint(c_default="DEF_BUF_SIZE") = DEF_BUF_SIZE
276276
The initial output buffer size.
277277
/
@@ -282,7 +282,7 @@ Returns a bytes object containing the uncompressed data.
282282
static PyObject *
283283
zlib_decompress_impl(PyModuleDef *module, Py_buffer *data, int wbits,
284284
unsigned int bufsize)
285-
/*[clinic end generated code: output=444d0987f3429574 input=da095118b3243b27]*/
285+
/*[clinic end generated code: output=444d0987f3429574 input=75123b0d4ff0541d]*/
286286
{
287287
PyObject *result_str = NULL;
288288
Byte *input;
@@ -396,7 +396,10 @@ zlib.compressobj
396396
method: int(c_default="DEFLATED") = DEFLATED
397397
The compression algorithm. If given, this must be DEFLATED.
398398
wbits: int(c_default="MAX_WBITS") = MAX_WBITS
399-
The base two logarithm of the window size (range: 8..15).
399+
+9 to +15: The base-two logarithm of the window size. Include a zlib
400+
container.
401+
-9 to -15: Generate a raw stream.
402+
+25 to +31: Include a gzip container.
400403
memLevel: int(c_default="DEF_MEM_LEVEL") = DEF_MEM_LEVEL
401404
Controls the amount of memory used for internal compression state.
402405
Valid values range from 1 to 9. Higher values result in higher memory
@@ -414,7 +417,7 @@ Return a compressor object.
414417
static PyObject *
415418
zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits,
416419
int memLevel, int strategy, Py_buffer *zdict)
417-
/*[clinic end generated code: output=2949bbb9a5723ccd input=de2ffab6e910cd8b]*/
420+
/*[clinic end generated code: output=2949bbb9a5723ccd input=2fa3d026f90ab8d5]*/
418421
{
419422
compobject *self = NULL;
420423
int err;
@@ -475,7 +478,7 @@ zlib_compressobj_impl(PyModuleDef *module, int level, int method, int wbits,
475478
zlib.decompressobj
476479
477480
wbits: int(c_default="MAX_WBITS") = MAX_WBITS
478-
The window buffer size.
481+
The window buffer size and container format.
479482
zdict: object(c_default="NULL") = b''
480483
The predefined compression dictionary. This must be the same
481484
dictionary as used by the compressor that produced the input data.
@@ -485,7 +488,7 @@ Return a decompressor object.
485488

486489
static PyObject *
487490
zlib_decompressobj_impl(PyModuleDef *module, int wbits, PyObject *zdict)
488-
/*[clinic end generated code: output=8ccd583fbd631798 input=67f05145a6920127]*/
491+
/*[clinic end generated code: output=8ccd583fbd631798 input=d3832b8511fc977b]*/
489492
{
490493
int err;
491494
compobject *self;
@@ -1329,7 +1332,7 @@ PyDoc_STRVAR(zlib_module_documentation,
13291332
"decompress(string,[wbits],[bufsize]) -- Decompresses a compressed string.\n"
13301333
"decompressobj([wbits[, zdict]]]) -- Return a decompressor object.\n"
13311334
"\n"
1332-
"'wbits' is window buffer size.\n"
1335+
"'wbits' is window buffer size and container format.\n"
13331336
"Compressor objects support compress() and flush() methods; decompressor\n"
13341337
"objects support decompress() and flush().");
13351338

0 commit comments

Comments
 (0)