Author: Julian Berman <[email protected]>
Branch: zlib-copying
Changeset: r95835:51b646896e26
Date: 2019-02-05 13:46 +0100
http://bitbucket.org/pypy/pypy/changeset/51b646896e26/

Log:    Now implement decompressobj.copy at the language level.

        Something seems likely to be broken still because the contents of
        unused_data and unconsumed_tail aren't passed along to the copy...
        But we can come back and fix that in a minute, no tests are
        currently failing.

diff --git a/pypy/module/zlib/interp_zlib.py b/pypy/module/zlib/interp_zlib.py
--- a/pypy/module/zlib/interp_zlib.py
+++ b/pypy/module/zlib/interp_zlib.py
@@ -241,7 +241,14 @@
     Wrapper around zlib's z_stream structure which provides convenient
     decompression functionality.
     """
-    def __init__(self, space, wbits=rzlib.MAX_WBITS):
+    def __init__(
+        self,
+        space,
+        wbits=rzlib.MAX_WBITS,
+        stream=None,
+        unused_data="",
+        unconsumed_tail="",
+    ):
         """
         Initialize a new decompression object.
 
@@ -251,14 +258,18 @@
         inflateInit2.
         """
         ZLibObject.__init__(self, space)
-        self.unused_data = ''
-        self.unconsumed_tail = ''
-        try:
-            self.stream = rzlib.inflateInit(wbits)
-        except rzlib.RZlibError as e:
-            raise zlib_error(space, e.msg)
-        except ValueError:
-            raise oefmt(space.w_ValueError, "Invalid initialization option")
+
+        if stream is None:
+            try:
+                stream = rzlib.inflateInit(wbits)
+            except rzlib.RZlibError as e:
+                raise zlib_error(space, e.msg)
+            except ValueError:
+                raise oefmt(space.w_ValueError, "Invalid initialization 
option")
+        self.space = space
+        self.stream = stream
+        self.unused_data = unused_data
+        self.unconsumed_tail = unconsumed_tail
         self.register_finalizer(space)
 
     def _finalize_(self):
@@ -305,6 +316,19 @@
         self._save_unconsumed_input(data, finished, unused_len)
         return space.newbytes(string)
 
+    def copy(self, space):
+        try:
+            copied = rzlib.inflateCopy(self.stream)
+        except rzlib.RZlibError as e:
+            raise zlib_error(space, e.msg)
+
+        return Decompress(
+            space=self.space,
+            stream=copied,
+            # unused_data=self.unused_data,
+            # unconsumed_tail=self.unconsumed_tail,
+        )
+
     def flush(self, space, w_length=None):
         """
         flush( [length] ) -- This is kept for backward compatibility,
@@ -345,6 +369,7 @@
 Decompress.typedef = TypeDef(
     'Decompress',
     __new__ = interp2app(Decompress___new__),
+    copy = interp2app(Decompress.copy),
     decompress = interp2app(Decompress.decompress),
     flush = interp2app(Decompress.flush),
     unused_data = interp_attrproperty('unused_data', Decompress, 
wrapfn="newbytes"),
diff --git a/pypy/module/zlib/test/test_zlib.py 
b/pypy/module/zlib/test/test_zlib.py
--- a/pypy/module/zlib/test/test_zlib.py
+++ b/pypy/module/zlib/test/test_zlib.py
@@ -8,8 +8,10 @@
 except ImportError:
     import py; py.test.skip("no zlib module on this host Python")
 
+from pypy.interpreter.gateway import interp2app
 try:
     from pypy.module.zlib import interp_zlib
+    from rpython.rlib import rzlib
 except ImportError:
     import py; py.test.skip("no zlib C library on this machine")
 
@@ -38,6 +40,22 @@
         cls.w_expanded = cls.space.wrap(expanded)
         cls.w_compressed = cls.space.wrap(zlib.compress(expanded))
 
+        def intentionally_break_a_z_stream(space, w_zobj):
+            """
+            Intentionally break the z_stream associated with a
+            compressobj or decompressobj in a way that causes their copy
+            methods to raise RZlibErrors.
+            """
+            from rpython.rtyper.lltypesystem import rffi, lltype
+            w_zobj.stream.c_zalloc = rffi.cast(
+                lltype.typeOf(w_zobj.stream.c_zalloc),
+                rzlib.Z_NULL,
+            )
+
+        cls.w_intentionally_break_a_z_stream = cls.space.wrap(
+            interp2app(intentionally_break_a_z_stream),
+        )
+
     def test_error(self):
         """
         zlib.error should be an exception class.
@@ -276,3 +294,20 @@
         assert dco.flush(1) == input1[1:]
         assert dco.unused_data == b''
         assert dco.unconsumed_tail == b''
+
+    def test_decompress_copy(self):
+        decompressor = self.zlib.decompressobj()
+        d1 = decompressor.decompress(self.compressed[:10])
+        assert d1
+
+        copied = decompressor.copy()
+
+        from_copy = copied.decompress(self.compressed[10:])
+        from_decompressor = decompressor.decompress(self.compressed[10:])
+
+        assert (d1 + from_copy) == (d1 + from_decompressor)
+
+    def test_unsuccessful_decompress_copy(self):
+        decompressor = self.zlib.decompressobj()
+        self.intentionally_break_a_z_stream(zobj=decompressor)
+        raises(self.zlib.error, decompressor.copy)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to