From d2cbfffc842b00b5257aa1c25dbcdeb456b6a249 Mon Sep 17 00:00:00 2001 From: Zackery Spytz Date: Wed, 27 Jun 2018 12:04:51 -0600 Subject: [PATCH] bpo-25007: Add copy protocol support to zlib compressors and decompressors (GH-7940) --- Doc/library/zlib.rst | 10 +++ Lib/test/test_zlib.py | 55 ++++++------ .../2018-06-26-16-55-59.bpo-25007.6LQWOF.rst | 2 + Modules/clinic/zlibmodule.c.h | 84 ++++++++++++++++++- Modules/zlibmodule.c | 57 +++++++++++++ 5 files changed, 183 insertions(+), 25 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2018-06-26-16-55-59.bpo-25007.6LQWOF.rst diff --git a/Doc/library/zlib.rst b/Doc/library/zlib.rst index 8a531c92b8f..aa61278e099 100644 --- a/Doc/library/zlib.rst +++ b/Doc/library/zlib.rst @@ -231,6 +231,11 @@ Compression objects support the following methods: compress a set of data that share a common initial prefix. +.. versionchanged:: 3.8 + Added :func:`copy.copy` and :func:`copy.deepcopy` support to compression + objects. + + Decompression objects support the following methods and attributes: @@ -298,6 +303,11 @@ Decompression objects support the following methods and attributes: seeks into the stream at a future point. +.. versionchanged:: 3.8 + Added :func:`copy.copy` and :func:`copy.deepcopy` support to decompression + objects. + + Information about the version of the zlib library in use is available through the following constants: diff --git a/Lib/test/test_zlib.py b/Lib/test/test_zlib.py index 99aa89bdc8c..4871d60d756 100644 --- a/Lib/test/test_zlib.py +++ b/Lib/test/test_zlib.py @@ -1,6 +1,7 @@ import unittest from test import support import binascii +import copy import pickle import random import sys @@ -626,23 +627,24 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): # Test copying a compression object data0 = HAMLET_SCENE data1 = bytes(str(HAMLET_SCENE, "ascii").swapcase(), "ascii") - c0 = zlib.compressobj(zlib.Z_BEST_COMPRESSION) - bufs0 = [] - bufs0.append(c0.compress(data0)) + for func in lambda c: c.copy(), copy.copy, copy.deepcopy: + c0 = zlib.compressobj(zlib.Z_BEST_COMPRESSION) + bufs0 = [] + bufs0.append(c0.compress(data0)) - c1 = c0.copy() - bufs1 = bufs0[:] + c1 = func(c0) + bufs1 = bufs0[:] - bufs0.append(c0.compress(data0)) - bufs0.append(c0.flush()) - s0 = b''.join(bufs0) + bufs0.append(c0.compress(data0)) + bufs0.append(c0.flush()) + s0 = b''.join(bufs0) - bufs1.append(c1.compress(data1)) - bufs1.append(c1.flush()) - s1 = b''.join(bufs1) + bufs1.append(c1.compress(data1)) + bufs1.append(c1.flush()) + s1 = b''.join(bufs1) - self.assertEqual(zlib.decompress(s0),data0+data0) - self.assertEqual(zlib.decompress(s1),data0+data1) + self.assertEqual(zlib.decompress(s0),data0+data0) + self.assertEqual(zlib.decompress(s1),data0+data1) @requires_Compress_copy def test_badcompresscopy(self): @@ -651,6 +653,8 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): c.compress(HAMLET_SCENE) c.flush() self.assertRaises(ValueError, c.copy) + self.assertRaises(ValueError, copy.copy, c) + self.assertRaises(ValueError, copy.deepcopy, c) @requires_Decompress_copy def test_decompresscopy(self): @@ -660,21 +664,22 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): # Test type of return value self.assertIsInstance(comp, bytes) - d0 = zlib.decompressobj() - bufs0 = [] - bufs0.append(d0.decompress(comp[:32])) + for func in lambda c: c.copy(), copy.copy, copy.deepcopy: + d0 = zlib.decompressobj() + bufs0 = [] + bufs0.append(d0.decompress(comp[:32])) - d1 = d0.copy() - bufs1 = bufs0[:] + d1 = func(d0) + bufs1 = bufs0[:] - bufs0.append(d0.decompress(comp[32:])) - s0 = b''.join(bufs0) + bufs0.append(d0.decompress(comp[32:])) + s0 = b''.join(bufs0) - bufs1.append(d1.decompress(comp[32:])) - s1 = b''.join(bufs1) + bufs1.append(d1.decompress(comp[32:])) + s1 = b''.join(bufs1) - self.assertEqual(s0,s1) - self.assertEqual(s0,data) + self.assertEqual(s0,s1) + self.assertEqual(s0,data) @requires_Decompress_copy def test_baddecompresscopy(self): @@ -684,6 +689,8 @@ class CompressObjectTestCase(BaseCompressTestCase, unittest.TestCase): d.decompress(data) d.flush() self.assertRaises(ValueError, d.copy) + self.assertRaises(ValueError, copy.copy, d) + self.assertRaises(ValueError, copy.deepcopy, d) def test_compresspickle(self): for proto in range(pickle.HIGHEST_PROTOCOL + 1): diff --git a/Misc/NEWS.d/next/Library/2018-06-26-16-55-59.bpo-25007.6LQWOF.rst b/Misc/NEWS.d/next/Library/2018-06-26-16-55-59.bpo-25007.6LQWOF.rst new file mode 100644 index 00000000000..b7d832be1ad --- /dev/null +++ b/Misc/NEWS.d/next/Library/2018-06-26-16-55-59.bpo-25007.6LQWOF.rst @@ -0,0 +1,2 @@ +Add :func:`copy.copy` and :func:`copy.deepcopy` support to zlib compressors +and decompressors. Patch by Zackery Spytz. diff --git a/Modules/clinic/zlibmodule.c.h b/Modules/clinic/zlibmodule.c.h index c68c4a10785..99db052bf2f 100644 --- a/Modules/clinic/zlibmodule.c.h +++ b/Modules/clinic/zlibmodule.c.h @@ -335,6 +335,39 @@ zlib_Compress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) #if defined(HAVE_ZLIB_COPY) +PyDoc_STRVAR(zlib_Compress___copy____doc__, +"__copy__($self, /)\n" +"--\n" +"\n"); + +#define ZLIB_COMPRESS___COPY___METHODDEF \ + {"__copy__", (PyCFunction)zlib_Compress___copy__, METH_NOARGS, zlib_Compress___copy____doc__}, + +static PyObject * +zlib_Compress___copy___impl(compobject *self); + +static PyObject * +zlib_Compress___copy__(compobject *self, PyObject *Py_UNUSED(ignored)) +{ + return zlib_Compress___copy___impl(self); +} + +#endif /* defined(HAVE_ZLIB_COPY) */ + +#if defined(HAVE_ZLIB_COPY) + +PyDoc_STRVAR(zlib_Compress___deepcopy____doc__, +"__deepcopy__($self, memo, /)\n" +"--\n" +"\n"); + +#define ZLIB_COMPRESS___DEEPCOPY___METHODDEF \ + {"__deepcopy__", (PyCFunction)zlib_Compress___deepcopy__, METH_O, zlib_Compress___deepcopy____doc__}, + +#endif /* defined(HAVE_ZLIB_COPY) */ + +#if defined(HAVE_ZLIB_COPY) + PyDoc_STRVAR(zlib_Decompress_copy__doc__, "copy($self, /)\n" "--\n" @@ -355,6 +388,39 @@ zlib_Decompress_copy(compobject *self, PyObject *Py_UNUSED(ignored)) #endif /* defined(HAVE_ZLIB_COPY) */ +#if defined(HAVE_ZLIB_COPY) + +PyDoc_STRVAR(zlib_Decompress___copy____doc__, +"__copy__($self, /)\n" +"--\n" +"\n"); + +#define ZLIB_DECOMPRESS___COPY___METHODDEF \ + {"__copy__", (PyCFunction)zlib_Decompress___copy__, METH_NOARGS, zlib_Decompress___copy____doc__}, + +static PyObject * +zlib_Decompress___copy___impl(compobject *self); + +static PyObject * +zlib_Decompress___copy__(compobject *self, PyObject *Py_UNUSED(ignored)) +{ + return zlib_Decompress___copy___impl(self); +} + +#endif /* defined(HAVE_ZLIB_COPY) */ + +#if defined(HAVE_ZLIB_COPY) + +PyDoc_STRVAR(zlib_Decompress___deepcopy____doc__, +"__deepcopy__($self, memo, /)\n" +"--\n" +"\n"); + +#define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF \ + {"__deepcopy__", (PyCFunction)zlib_Decompress___deepcopy__, METH_O, zlib_Decompress___deepcopy____doc__}, + +#endif /* defined(HAVE_ZLIB_COPY) */ + PyDoc_STRVAR(zlib_Decompress_flush__doc__, "flush($self, length=zlib.DEF_BUF_SIZE, /)\n" "--\n" @@ -468,7 +534,23 @@ exit: #define ZLIB_COMPRESS_COPY_METHODDEF #endif /* !defined(ZLIB_COMPRESS_COPY_METHODDEF) */ +#ifndef ZLIB_COMPRESS___COPY___METHODDEF + #define ZLIB_COMPRESS___COPY___METHODDEF +#endif /* !defined(ZLIB_COMPRESS___COPY___METHODDEF) */ + +#ifndef ZLIB_COMPRESS___DEEPCOPY___METHODDEF + #define ZLIB_COMPRESS___DEEPCOPY___METHODDEF +#endif /* !defined(ZLIB_COMPRESS___DEEPCOPY___METHODDEF) */ + #ifndef ZLIB_DECOMPRESS_COPY_METHODDEF #define ZLIB_DECOMPRESS_COPY_METHODDEF #endif /* !defined(ZLIB_DECOMPRESS_COPY_METHODDEF) */ -/*[clinic end generated code: output=43dd29b8977765f9 input=a9049054013a1b77]*/ + +#ifndef ZLIB_DECOMPRESS___COPY___METHODDEF + #define ZLIB_DECOMPRESS___COPY___METHODDEF +#endif /* !defined(ZLIB_DECOMPRESS___COPY___METHODDEF) */ + +#ifndef ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF + #define ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF +#endif /* !defined(ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF) */ +/*[clinic end generated code: output=d46c646770146ade input=a9049054013a1b77]*/ diff --git a/Modules/zlibmodule.c b/Modules/zlibmodule.c index cd587b4ac9c..36a3835e421 100644 --- a/Modules/zlibmodule.c +++ b/Modules/zlibmodule.c @@ -984,6 +984,32 @@ error: return NULL; } +/*[clinic input] +zlib.Compress.__copy__ +[clinic start generated code]*/ + +static PyObject * +zlib_Compress___copy___impl(compobject *self) +/*[clinic end generated code: output=1875e6791975442e input=be97a05a788dfd83]*/ +{ + return zlib_Compress_copy_impl(self); +} + +/*[clinic input] +zlib.Compress.__deepcopy__ + + memo: object + / + +[clinic start generated code]*/ + +static PyObject * +zlib_Compress___deepcopy__(compobject *self, PyObject *memo) +/*[clinic end generated code: output=f47a2213282c9eb0 input=a9a8b0b40d83388e]*/ +{ + return zlib_Compress_copy_impl(self); +} + /*[clinic input] zlib.Decompress.copy @@ -1039,6 +1065,33 @@ error: Py_XDECREF(retval); return NULL; } + +/*[clinic input] +zlib.Decompress.__copy__ +[clinic start generated code]*/ + +static PyObject * +zlib_Decompress___copy___impl(compobject *self) +/*[clinic end generated code: output=80bae8bc43498ad4 input=efcb98b5472c13d2]*/ +{ + return zlib_Decompress_copy_impl(self); +} + +/*[clinic input] +zlib.Decompress.__deepcopy__ + + memo: object + / + +[clinic start generated code]*/ + +static PyObject * +zlib_Decompress___deepcopy__(compobject *self, PyObject *memo) +/*[clinic end generated code: output=1f77286ab490124b input=6e99bd0ac4b9cd8b]*/ +{ + return zlib_Decompress_copy_impl(self); +} + #endif /*[clinic input] @@ -1139,6 +1192,8 @@ static PyMethodDef comp_methods[] = ZLIB_COMPRESS_COMPRESS_METHODDEF ZLIB_COMPRESS_FLUSH_METHODDEF ZLIB_COMPRESS_COPY_METHODDEF + ZLIB_COMPRESS___COPY___METHODDEF + ZLIB_COMPRESS___DEEPCOPY___METHODDEF {NULL, NULL} }; @@ -1147,6 +1202,8 @@ static PyMethodDef Decomp_methods[] = ZLIB_DECOMPRESS_DECOMPRESS_METHODDEF ZLIB_DECOMPRESS_FLUSH_METHODDEF ZLIB_DECOMPRESS_COPY_METHODDEF + ZLIB_DECOMPRESS___COPY___METHODDEF + ZLIB_DECOMPRESS___DEEPCOPY___METHODDEF {NULL, NULL} };