Commit 77b338be authored by Antoine Pitrou's avatar Antoine Pitrou

Issue #4757: `zlib.compress` and other methods in the zlib module now

raise a TypeError when given an `str` object (rather than a `bytes`-like
object).  Patch by Victor Stinner and Florent Xicluna.
parent 338eae34
...@@ -147,7 +147,7 @@ class GzipFile: ...@@ -147,7 +147,7 @@ class GzipFile:
def _init_write(self, filename): def _init_write(self, filename):
self.name = filename self.name = filename
self.crc = zlib.crc32("") & 0xffffffff self.crc = zlib.crc32(b"") & 0xffffffff
self.size = 0 self.size = 0
self.writebuf = [] self.writebuf = []
self.bufsize = 0 self.bufsize = 0
...@@ -178,7 +178,7 @@ class GzipFile: ...@@ -178,7 +178,7 @@ class GzipFile:
self.fileobj.write(fname + b'\000') self.fileobj.write(fname + b'\000')
def _init_read(self): def _init_read(self):
self.crc = zlib.crc32("") & 0xffffffff self.crc = zlib.crc32(b"") & 0xffffffff
self.size = 0 self.size = 0
def _read_gzip_header(self): def _read_gzip_header(self):
......
...@@ -410,7 +410,7 @@ class _Stream: ...@@ -410,7 +410,7 @@ class _Stream:
except ImportError: except ImportError:
raise CompressionError("zlib module is not available") raise CompressionError("zlib module is not available")
self.zlib = zlib self.zlib = zlib
self.crc = zlib.crc32("") self.crc = zlib.crc32(b"")
if mode == "r": if mode == "r":
self._init_read_gz() self._init_read_gz()
else: else:
......
...@@ -41,12 +41,12 @@ class ChecksumTestCase(unittest.TestCase): ...@@ -41,12 +41,12 @@ class ChecksumTestCase(unittest.TestCase):
self.assertEqual(zlib.adler32(b"penguin"),zlib.adler32(b"penguin",1)) self.assertEqual(zlib.adler32(b"penguin"),zlib.adler32(b"penguin",1))
def test_crc32_adler32_unsigned(self): def test_crc32_adler32_unsigned(self):
foo = 'abcdefghijklmnop' foo = b'abcdefghijklmnop'
# explicitly test signed behavior # explicitly test signed behavior
self.assertEqual(zlib.crc32(foo), 2486878355) self.assertEqual(zlib.crc32(foo), 2486878355)
self.assertEqual(zlib.crc32('spam'), 1138425661) self.assertEqual(zlib.crc32(b'spam'), 1138425661)
self.assertEqual(zlib.adler32(foo+foo), 3573550353) self.assertEqual(zlib.adler32(foo+foo), 3573550353)
self.assertEqual(zlib.adler32('spam'), 72286642) self.assertEqual(zlib.adler32(b'spam'), 72286642)
def test_same_as_binascii_crc32(self): def test_same_as_binascii_crc32(self):
foo = b'abcdefghijklmnop' foo = b'abcdefghijklmnop'
...@@ -63,7 +63,18 @@ class ExceptionTestCase(unittest.TestCase): ...@@ -63,7 +63,18 @@ class ExceptionTestCase(unittest.TestCase):
# specifying compression level out of range causes an error # specifying compression level out of range causes an error
# (but -1 is Z_DEFAULT_COMPRESSION and apparently the zlib # (but -1 is Z_DEFAULT_COMPRESSION and apparently the zlib
# accepts 0 too) # accepts 0 too)
self.assertRaises(zlib.error, zlib.compress, 'ERROR', 10) self.assertRaises(zlib.error, zlib.compress, b'ERROR', 10)
def test_badargs(self):
self.assertRaises(TypeError, zlib.adler32)
self.assertRaises(TypeError, zlib.crc32)
self.assertRaises(TypeError, zlib.compress)
self.assertRaises(TypeError, zlib.decompress)
for arg in (42, None, '', 'abc', (), []):
self.assertRaises(TypeError, zlib.adler32, arg)
self.assertRaises(TypeError, zlib.crc32, arg)
self.assertRaises(TypeError, zlib.compress, arg)
self.assertRaises(TypeError, zlib.decompress, arg)
def test_badcompressobj(self): def test_badcompressobj(self):
# verify failure on building compress object with bad params # verify failure on building compress object with bad params
...@@ -93,8 +104,9 @@ class CompressTestCase(unittest.TestCase): ...@@ -93,8 +104,9 @@ class CompressTestCase(unittest.TestCase):
# compress more data # compress more data
data = HAMLET_SCENE * 128 data = HAMLET_SCENE * 128
x = zlib.compress(data) x = zlib.compress(data)
self.assertEqual(zlib.decompress(x), data) self.assertEqual(zlib.compress(bytearray(data)), x)
for ob in x, bytearray(x):
self.assertEqual(zlib.decompress(ob), data)
...@@ -102,17 +114,22 @@ class CompressObjectTestCase(unittest.TestCase): ...@@ -102,17 +114,22 @@ class CompressObjectTestCase(unittest.TestCase):
# Test compression object # Test compression object
def test_pair(self): def test_pair(self):
# straightforward compress/decompress objects # straightforward compress/decompress objects
data = HAMLET_SCENE * 128 datasrc = HAMLET_SCENE * 128
co = zlib.compressobj() datazip = zlib.compress(datasrc)
x1 = co.compress(data) # should compress both bytes and bytearray data
x2 = co.flush() for data in (datasrc, bytearray(datasrc)):
self.assertRaises(zlib.error, co.flush) # second flush should not work co = zlib.compressobj()
dco = zlib.decompressobj() x1 = co.compress(data)
y1 = dco.decompress(x1 + x2) x2 = co.flush()
y2 = dco.flush() self.assertRaises(zlib.error, co.flush) # second flush should not work
self.assertEqual(data, y1 + y2) self.assertEqual(x1 + x2, datazip)
self.assertTrue(isinstance(dco.unconsumed_tail, bytes)) for v1, v2 in ((x1, x2), (bytearray(x1), bytearray(x2))):
self.assertTrue(isinstance(dco.unused_data, bytes)) dco = zlib.decompressobj()
y1 = dco.decompress(v1 + v2)
y2 = dco.flush()
self.assertEqual(data, y1 + y2)
self.assertIsInstance(dco.unconsumed_tail, bytes)
self.assertIsInstance(dco.unused_data, bytes)
def test_compressoptions(self): def test_compressoptions(self):
# specify lots of options to compressobj() # specify lots of options to compressobj()
...@@ -173,7 +190,7 @@ class CompressObjectTestCase(unittest.TestCase): ...@@ -173,7 +190,7 @@ class CompressObjectTestCase(unittest.TestCase):
bufs.append(dco.flush()) bufs.append(dco.flush())
else: else:
while True: while True:
chunk = dco.decompress('') chunk = dco.decompress(b'')
if chunk: if chunk:
bufs.append(chunk) bufs.append(chunk)
else: else:
...@@ -241,7 +258,7 @@ class CompressObjectTestCase(unittest.TestCase): ...@@ -241,7 +258,7 @@ class CompressObjectTestCase(unittest.TestCase):
bufs.append(dco.flush()) bufs.append(dco.flush())
else: else:
while chunk: while chunk:
chunk = dco.decompress('', max_length) chunk = dco.decompress(b'', max_length)
self.assertFalse(len(chunk) > max_length, self.assertFalse(len(chunk) > max_length,
'chunk too big (%d>%d)' % (len(chunk),max_length)) 'chunk too big (%d>%d)' % (len(chunk),max_length))
bufs.append(chunk) bufs.append(chunk)
...@@ -253,7 +270,7 @@ class CompressObjectTestCase(unittest.TestCase): ...@@ -253,7 +270,7 @@ class CompressObjectTestCase(unittest.TestCase):
def test_maxlenmisc(self): def test_maxlenmisc(self):
# Misc tests of max_length # Misc tests of max_length
dco = zlib.decompressobj() dco = zlib.decompressobj()
self.assertRaises(ValueError, dco.decompress, "", -1) self.assertRaises(ValueError, dco.decompress, b"", -1)
self.assertEqual(b'', dco.unconsumed_tail) self.assertEqual(b'', dco.unconsumed_tail)
def test_flushes(self): def test_flushes(self):
......
...@@ -157,6 +157,10 @@ C-API ...@@ -157,6 +157,10 @@ C-API
Library Library
------- -------
- Issue #4757: `zlib.compress` and other methods in the zlib module now
raise a TypeError when given an `str` object (rather than a `bytes`-like
object). Patch by Victor Stinner and Florent Xicluna.
- Issue #7349: Make methods of file objects in the io module accept None as an - Issue #7349: Make methods of file objects in the io module accept None as an
argument where file-like objects (ie StringIO and BytesIO) accept them to mean argument where file-like objects (ie StringIO and BytesIO) accept them to mean
the same as passing no argument. the same as passing no argument.
......
...@@ -107,7 +107,7 @@ PyZlib_compress(PyObject *self, PyObject *args) ...@@ -107,7 +107,7 @@ PyZlib_compress(PyObject *self, PyObject *args)
z_stream zst; z_stream zst;
/* require Python string object, optional 'level' arg */ /* require Python string object, optional 'level' arg */
if (!PyArg_ParseTuple(args, "s*|i:compress", &pinput, &level)) if (!PyArg_ParseTuple(args, "y*|i:compress", &pinput, &level))
return NULL; return NULL;
input = pinput.buf; input = pinput.buf;
length = pinput.len; length = pinput.len;
...@@ -190,7 +190,7 @@ PyZlib_decompress(PyObject *self, PyObject *args) ...@@ -190,7 +190,7 @@ PyZlib_decompress(PyObject *self, PyObject *args)
Py_ssize_t r_strlen=DEFAULTALLOC; Py_ssize_t r_strlen=DEFAULTALLOC;
z_stream zst; z_stream zst;
if (!PyArg_ParseTuple(args, "s*|in:decompress", if (!PyArg_ParseTuple(args, "y*|in:decompress",
&pinput, &wsize, &r_strlen)) &pinput, &wsize, &r_strlen))
return NULL; return NULL;
input = pinput.buf; input = pinput.buf;
...@@ -402,7 +402,7 @@ PyZlib_objcompress(compobject *self, PyObject *args) ...@@ -402,7 +402,7 @@ PyZlib_objcompress(compobject *self, PyObject *args)
Byte *input; Byte *input;
unsigned long start_total_out; unsigned long start_total_out;
if (!PyArg_ParseTuple(args, "s*:compress", &pinput)) if (!PyArg_ParseTuple(args, "y*:compress", &pinput))
return NULL; return NULL;
input = pinput.buf; input = pinput.buf;
inplen = pinput.len; inplen = pinput.len;
...@@ -484,7 +484,7 @@ PyZlib_objdecompress(compobject *self, PyObject *args) ...@@ -484,7 +484,7 @@ PyZlib_objdecompress(compobject *self, PyObject *args)
Byte *input; Byte *input;
unsigned long start_total_out; unsigned long start_total_out;
if (!PyArg_ParseTuple(args, "s*|i:decompress", &pinput, if (!PyArg_ParseTuple(args, "y*|i:decompress", &pinput,
&max_length)) &max_length))
return NULL; return NULL;
input = pinput.buf; input = pinput.buf;
...@@ -912,8 +912,8 @@ PyZlib_adler32(PyObject *self, PyObject *args) ...@@ -912,8 +912,8 @@ PyZlib_adler32(PyObject *self, PyObject *args)
unsigned int adler32val = 1; /* adler32(0L, Z_NULL, 0) */ unsigned int adler32val = 1; /* adler32(0L, Z_NULL, 0) */
Py_buffer pbuf; Py_buffer pbuf;
if (!PyArg_ParseTuple(args, "s*|I:adler32", &pbuf, &adler32val)) if (!PyArg_ParseTuple(args, "y*|I:adler32", &pbuf, &adler32val))
return NULL; return NULL;
/* Releasing the GIL for very small buffers is inefficient /* Releasing the GIL for very small buffers is inefficient
and may lower performance */ and may lower performance */
if (pbuf.len > 1024*5) { if (pbuf.len > 1024*5) {
...@@ -921,7 +921,7 @@ PyZlib_adler32(PyObject *self, PyObject *args) ...@@ -921,7 +921,7 @@ PyZlib_adler32(PyObject *self, PyObject *args)
adler32val = adler32(adler32val, pbuf.buf, pbuf.len); adler32val = adler32(adler32val, pbuf.buf, pbuf.len);
Py_END_ALLOW_THREADS Py_END_ALLOW_THREADS
} else { } else {
adler32val = adler32(adler32val, pbuf.buf, pbuf.len); adler32val = adler32(adler32val, pbuf.buf, pbuf.len);
} }
PyBuffer_Release(&pbuf); PyBuffer_Release(&pbuf);
return PyLong_FromUnsignedLong(adler32val & 0xffffffffU); return PyLong_FromUnsignedLong(adler32val & 0xffffffffU);
...@@ -940,7 +940,7 @@ PyZlib_crc32(PyObject *self, PyObject *args) ...@@ -940,7 +940,7 @@ PyZlib_crc32(PyObject *self, PyObject *args)
Py_buffer pbuf; Py_buffer pbuf;
int signed_val; int signed_val;
if (!PyArg_ParseTuple(args, "s*|I:crc32", &pbuf, &crc32val)) if (!PyArg_ParseTuple(args, "y*|I:crc32", &pbuf, &crc32val))
return NULL; return NULL;
/* Releasing the GIL for very small buffers is inefficient /* Releasing the GIL for very small buffers is inefficient
and may lower performance */ and may lower performance */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment