]> granicus.if.org Git - python/commitdiff
Issue #9962: GzipFile now has the peek() method.
authorAntoine Pitrou <solipsis@pitrou.net>
Wed, 29 Sep 2010 10:49:46 +0000 (10:49 +0000)
committerAntoine Pitrou <solipsis@pitrou.net>
Wed, 29 Sep 2010 10:49:46 +0000 (10:49 +0000)
Doc/library/gzip.rst
Lib/gzip.py
Lib/test/test_gzip.py
Misc/NEWS

index dc04ba0b17e4f5eb35f7787cf627269d75a7e578..0ae23d2d6b7a4bcfacf8b41aa8769293ff781526 100644 (file)
@@ -25,10 +25,10 @@ The module defines the following items:
 
 .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
 
-   Constructor for the :class:`GzipFile` class, which simulates most of the methods
-   of a :term:`file object`, with the exception of the :meth:`readinto` and
-   :meth:`truncate` methods.  At least one of *fileobj* and *filename* must be
-   given a non-trivial value.
+   Constructor for the :class:`GzipFile` class, which simulates most of the
+   methods of a :term:`file object`, with the exception of the :meth:`truncate`
+   method.  At least one of *fileobj* and *filename* must be given a non-trivial
+   value.
 
    The new class instance is based on *fileobj*, which can be a regular file, a
    :class:`StringIO` object, or any other object which simulates a file.  It
@@ -66,8 +66,9 @@ The module defines the following items:
    writing as *fileobj*, and retrieve the resulting memory buffer using the
    :class:`io.BytesIO` object's :meth:`~io.BytesIO.getvalue` method.
 
-   :class:`GzipFile` supports the whole :class:`io.BufferedIOBase` interface,
-   including iteration and the :keyword:`with` statement.
+   :class:`GzipFile` supports the :class:`io.BufferedIOBase` interface,
+   including iteration and the :keyword:`with` statement.  Only the
+   :meth:`truncate` method isn't implemented.
 
    .. versionchanged:: 3.1
       Support for the :keyword:`with` statement was added.
@@ -78,6 +79,9 @@ The module defines the following items:
    .. versionchanged:: 3.2
       Support for unseekable files was added.
 
+   .. versionchanged:: 3.2
+      The :meth:`peek` method was implemented.
+
 
 .. function:: open(filename, mode='rb', compresslevel=9)
 
index 3edc8395d68a9ef51838345a44ea4690f37943f6..58e866b132d1cabdb28995bd8e44c1a514d222e2 100644 (file)
@@ -204,7 +204,10 @@ class GzipFile(io.BufferedIOBase):
         return self.name
 
     def __repr__(self):
-        s = repr(self.fileobj)
+        fileobj = self.fileobj
+        if isinstance(fileobj, _PaddedFile):
+            fileobj = fileobj.file
+        s = repr(fileobj)
         return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
 
     def _init_write(self, filename):
@@ -336,6 +339,26 @@ class GzipFile(io.BufferedIOBase):
         self.offset += size
         return chunk
 
+    def peek(self, n):
+        if self.mode != READ:
+            import errno
+            raise IOError(errno.EBADF, "read() on write-only GzipFile object")
+
+        # Do not return ridiculously small buffers
+        if n < 100:
+            n = 100
+        if self.extrasize == 0:
+            if self.fileobj is None:
+                return b''
+            try:
+                self._read(max(self.max_read_chunk, n))
+            except EOFError:
+                pass
+        offset = self.offset - self.extrastart
+        remaining = self.extrasize
+        assert remaining == len(self.extrabuf) - offset
+        return self.extrabuf[offset:offset + n]
+
     def _unread(self, buf):
         self.extrasize = len(buf) + self.extrasize
         self.offset -= len(buf)
index e49fe00802b778afa91ac5f671a922a3a45db4aa..8e493b500002071cbb6edd66c56930e91c39524c 100644 (file)
@@ -286,6 +286,28 @@ class TestGzip(unittest.TestCase):
         with gzip.GzipFile(fileobj=buf, mode="rb") as f:
             self.assertEqual(f.read(), uncompressed)
 
+    def test_peek(self):
+        uncompressed = data1 * 200
+        with gzip.GzipFile(self.filename, "wb") as f:
+            f.write(uncompressed)
+
+        def sizes():
+            while True:
+                for n in range(5, 50, 10):
+                    yield n
+
+        with gzip.GzipFile(self.filename, "rb") as f:
+            f.max_read_chunk = 33
+            nread = 0
+            for n in sizes():
+                s = f.peek(n)
+                if s == b'':
+                    break
+                self.assertEqual(f.read(len(s)), s)
+                nread += len(s)
+            self.assertEqual(f.read(100), b'')
+            self.assertEqual(nread, len(uncompressed))
+
     # Testing compress/decompress shortcut functions
 
     def test_compress(self):
index f77492606941e218deacdc80fe3643bd921adbd6..0daba085c7eec8e0cda7f2df1f25d1f0bd8ba530 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -76,6 +76,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #9962: GzipFile now has the peek() method.
+
 - Issue #9090: When a socket with a timeout fails with EWOULDBLOCK or EAGAIN,
   retry the select() loop instead of bailing out.  This is because select()
   can incorrectly report a socket as ready for reading (for example, if it