Patch #1435422: zlib's compress and decompress objects now have a
copy() method.
This commit is contained in:
parent
5f5d99c215
commit
8d3342b489
|
@ -123,6 +123,12 @@ prevents compressing any more data. After calling
|
||||||
action is to delete the object.
|
action is to delete the object.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
|
\begin{methoddesc}[Compress]{copy}{}
|
||||||
|
Returns a copy of the compression object. This can be used to efficiently
|
||||||
|
compress a set of data that share a common initial prefix.
|
||||||
|
\versionadded{2.5}
|
||||||
|
\end{methoddesc}
|
||||||
|
|
||||||
Decompression objects support the following methods, and two attributes:
|
Decompression objects support the following methods, and two attributes:
|
||||||
|
|
||||||
\begin{memberdesc}{unused_data}
|
\begin{memberdesc}{unused_data}
|
||||||
|
@ -176,6 +182,13 @@ The optional parameter \var{length} sets the initial size of the
|
||||||
output buffer.
|
output buffer.
|
||||||
\end{methoddesc}
|
\end{methoddesc}
|
||||||
|
|
||||||
|
\begin{methoddesc}[Decompress]{copy}{}
|
||||||
|
Returns a copy of the decompression object. This can be used to save the
|
||||||
|
state of the decompressor midway through the data stream in order to speed up
|
||||||
|
random seeks into the stream at a future point.
|
||||||
|
\versionadded{2.5}
|
||||||
|
\end{methoddesc}
|
||||||
|
|
||||||
\begin{seealso}
|
\begin{seealso}
|
||||||
\seemodule{gzip}{Reading and writing \program{gzip}-format files.}
|
\seemodule{gzip}{Reading and writing \program{gzip}-format files.}
|
||||||
\seeurl{http://www.zlib.net}{The zlib library home page.}
|
\seeurl{http://www.zlib.net}{The zlib library home page.}
|
||||||
|
|
|
@ -302,6 +302,63 @@ class CompressObjectTestCase(unittest.TestCase):
|
||||||
dco = zlib.decompressobj()
|
dco = zlib.decompressobj()
|
||||||
self.assertEqual(dco.flush(), "") # Returns nothing
|
self.assertEqual(dco.flush(), "") # Returns nothing
|
||||||
|
|
||||||
|
def test_compresscopy(self):
|
||||||
|
# Test copying a compression object
|
||||||
|
data0 = HAMLET_SCENE
|
||||||
|
data1 = HAMLET_SCENE.swapcase()
|
||||||
|
c0 = zlib.compressobj(zlib.Z_BEST_COMPRESSION)
|
||||||
|
bufs0 = []
|
||||||
|
bufs0.append(c0.compress(data0))
|
||||||
|
|
||||||
|
c1 = c0.copy()
|
||||||
|
bufs1 = bufs0[:]
|
||||||
|
|
||||||
|
bufs0.append(c0.compress(data0))
|
||||||
|
bufs0.append(c0.flush())
|
||||||
|
s0 = ''.join(bufs0)
|
||||||
|
|
||||||
|
bufs1.append(c1.compress(data1))
|
||||||
|
bufs1.append(c1.flush())
|
||||||
|
s1 = ''.join(bufs1)
|
||||||
|
|
||||||
|
self.assertEqual(zlib.decompress(s0),data0+data0)
|
||||||
|
self.assertEqual(zlib.decompress(s1),data0+data1)
|
||||||
|
|
||||||
|
def test_badcompresscopy(self):
|
||||||
|
# Test copying a compression object in an inconsistent state
|
||||||
|
c = zlib.compressobj()
|
||||||
|
c.compress(HAMLET_SCENE)
|
||||||
|
c.flush()
|
||||||
|
self.assertRaises(ValueError, c.copy)
|
||||||
|
|
||||||
|
def test_decompresscopy(self):
|
||||||
|
# Test copying a decompression object
|
||||||
|
data = HAMLET_SCENE
|
||||||
|
comp = zlib.compress(data)
|
||||||
|
|
||||||
|
d0 = zlib.decompressobj()
|
||||||
|
bufs0 = []
|
||||||
|
bufs0.append(d0.decompress(comp[:32]))
|
||||||
|
|
||||||
|
d1 = d0.copy()
|
||||||
|
bufs1 = bufs0[:]
|
||||||
|
|
||||||
|
bufs0.append(d0.decompress(comp[32:]))
|
||||||
|
s0 = ''.join(bufs0)
|
||||||
|
|
||||||
|
bufs1.append(d1.decompress(comp[32:]))
|
||||||
|
s1 = ''.join(bufs1)
|
||||||
|
|
||||||
|
self.assertEqual(s0,s1)
|
||||||
|
self.assertEqual(s0,data)
|
||||||
|
|
||||||
|
def test_baddecompresscopy(self):
|
||||||
|
# Test copying a compression object in an inconsistent state
|
||||||
|
data = zlib.compress(HAMLET_SCENE)
|
||||||
|
d = zlib.decompressobj()
|
||||||
|
d.decompress(data)
|
||||||
|
d.flush()
|
||||||
|
self.assertRaises(ValueError, d.copy)
|
||||||
|
|
||||||
def genblock(seed, length, step=1024, generator=random):
|
def genblock(seed, length, step=1024, generator=random):
|
||||||
"""length-byte stream of random data from a seed (in step-byte blocks)."""
|
"""length-byte stream of random data from a seed (in step-byte blocks)."""
|
||||||
|
|
|
@ -28,6 +28,9 @@ Core and builtins
|
||||||
Extension Modules
|
Extension Modules
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Patch #1435422: zlib's compress and decompress objects now have a
|
||||||
|
copy() method.
|
||||||
|
|
||||||
- On Win32, os.listdir now supports arbitrarily-long Unicode path names
|
- On Win32, os.listdir now supports arbitrarily-long Unicode path names
|
||||||
(up to the system limit of 32K characters).
|
(up to the system limit of 32K characters).
|
||||||
|
|
||||||
|
|
|
@ -653,6 +653,104 @@ PyZlib_flush(compobject *self, PyObject *args)
|
||||||
return RetVal;
|
return RetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(comp_copy__doc__,
|
||||||
|
"copy() -- Return a copy of the compression object.");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
PyZlib_copy(compobject *self)
|
||||||
|
{
|
||||||
|
compobject *retval = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
retval = newcompobject(&Comptype);
|
||||||
|
if (!retval) return NULL;
|
||||||
|
|
||||||
|
/* Copy the zstream state
|
||||||
|
* We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe
|
||||||
|
*/
|
||||||
|
ENTER_ZLIB
|
||||||
|
err = deflateCopy(&retval->zst, &self->zst);
|
||||||
|
switch(err) {
|
||||||
|
case(Z_OK):
|
||||||
|
break;
|
||||||
|
case(Z_STREAM_ERROR):
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Inconsistent stream state");
|
||||||
|
goto error;
|
||||||
|
case(Z_MEM_ERROR):
|
||||||
|
PyErr_SetString(PyExc_MemoryError,
|
||||||
|
"Can't allocate memory for compression object");
|
||||||
|
goto error;
|
||||||
|
default:
|
||||||
|
zlib_error(self->zst, err, "while copying compression object");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval->unused_data = self->unused_data;
|
||||||
|
retval->unconsumed_tail = self->unconsumed_tail;
|
||||||
|
Py_INCREF(retval->unused_data);
|
||||||
|
Py_INCREF(retval->unconsumed_tail);
|
||||||
|
|
||||||
|
/* Mark it as being initialized */
|
||||||
|
retval->is_initialised = 1;
|
||||||
|
|
||||||
|
LEAVE_ZLIB
|
||||||
|
return (PyObject *)retval;
|
||||||
|
|
||||||
|
error:
|
||||||
|
LEAVE_ZLIB
|
||||||
|
Py_XDECREF(retval);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(decomp_copy__doc__,
|
||||||
|
"copy() -- Return a copy of the decompression object.");
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
PyZlib_uncopy(compobject *self)
|
||||||
|
{
|
||||||
|
compobject *retval = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
retval = newcompobject(&Decomptype);
|
||||||
|
if (!retval) return NULL;
|
||||||
|
|
||||||
|
/* Copy the zstream state
|
||||||
|
* We use ENTER_ZLIB / LEAVE_ZLIB to make this thread-safe
|
||||||
|
*/
|
||||||
|
ENTER_ZLIB
|
||||||
|
err = inflateCopy(&retval->zst, &self->zst);
|
||||||
|
switch(err) {
|
||||||
|
case(Z_OK):
|
||||||
|
break;
|
||||||
|
case(Z_STREAM_ERROR):
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Inconsistent stream state");
|
||||||
|
goto error;
|
||||||
|
case(Z_MEM_ERROR):
|
||||||
|
PyErr_SetString(PyExc_MemoryError,
|
||||||
|
"Can't allocate memory for decompression object");
|
||||||
|
goto error;
|
||||||
|
default:
|
||||||
|
zlib_error(self->zst, err, "while copying decompression object");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
retval->unused_data = self->unused_data;
|
||||||
|
retval->unconsumed_tail = self->unconsumed_tail;
|
||||||
|
Py_INCREF(retval->unused_data);
|
||||||
|
Py_INCREF(retval->unconsumed_tail);
|
||||||
|
|
||||||
|
/* Mark it as being initialized */
|
||||||
|
retval->is_initialised = 1;
|
||||||
|
|
||||||
|
LEAVE_ZLIB
|
||||||
|
return (PyObject *)retval;
|
||||||
|
|
||||||
|
error:
|
||||||
|
LEAVE_ZLIB
|
||||||
|
Py_XDECREF(retval);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(decomp_flush__doc__,
|
PyDoc_STRVAR(decomp_flush__doc__,
|
||||||
"flush( [length] ) -- Return a string containing any remaining\n"
|
"flush( [length] ) -- Return a string containing any remaining\n"
|
||||||
"decompressed data. length, if given, is the initial size of the\n"
|
"decompressed data. length, if given, is the initial size of the\n"
|
||||||
|
@ -725,6 +823,8 @@ static PyMethodDef comp_methods[] =
|
||||||
comp_compress__doc__},
|
comp_compress__doc__},
|
||||||
{"flush", (binaryfunc)PyZlib_flush, METH_VARARGS,
|
{"flush", (binaryfunc)PyZlib_flush, METH_VARARGS,
|
||||||
comp_flush__doc__},
|
comp_flush__doc__},
|
||||||
|
{"copy", (PyCFunction)PyZlib_copy, METH_NOARGS,
|
||||||
|
comp_copy__doc__},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -734,6 +834,8 @@ static PyMethodDef Decomp_methods[] =
|
||||||
decomp_decompress__doc__},
|
decomp_decompress__doc__},
|
||||||
{"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS,
|
{"flush", (binaryfunc)PyZlib_unflush, METH_VARARGS,
|
||||||
decomp_flush__doc__},
|
decomp_flush__doc__},
|
||||||
|
{"copy", (PyCFunction)PyZlib_uncopy, METH_NOARGS,
|
||||||
|
decomp_copy__doc__},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue