Issue #9962: GzipFile now has the peek() method.

This commit is contained in:
Antoine Pitrou 2010-09-29 10:49:46 +00:00
parent 4c2e4fa242
commit c3ed2e7f83
4 changed files with 58 additions and 7 deletions

View File

@ -25,10 +25,10 @@ The module defines the following items:
.. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None) .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
Constructor for the :class:`GzipFile` class, which simulates most of the methods Constructor for the :class:`GzipFile` class, which simulates most of the
of a :term:`file object`, with the exception of the :meth:`readinto` and methods of a :term:`file object`, with the exception of the :meth:`truncate`
:meth:`truncate` methods. At least one of *fileobj* and *filename* must be method. At least one of *fileobj* and *filename* must be given a non-trivial
given a non-trivial value. value.
The new class instance is based on *fileobj*, which can be a regular file, a 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 :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 writing as *fileobj*, and retrieve the resulting memory buffer using the
:class:`io.BytesIO` object's :meth:`~io.BytesIO.getvalue` method. :class:`io.BytesIO` object's :meth:`~io.BytesIO.getvalue` method.
:class:`GzipFile` supports the whole :class:`io.BufferedIOBase` interface, :class:`GzipFile` supports the :class:`io.BufferedIOBase` interface,
including iteration and the :keyword:`with` statement. including iteration and the :keyword:`with` statement. Only the
:meth:`truncate` method isn't implemented.
.. versionchanged:: 3.1 .. versionchanged:: 3.1
Support for the :keyword:`with` statement was added. Support for the :keyword:`with` statement was added.
@ -78,6 +79,9 @@ The module defines the following items:
.. versionchanged:: 3.2 .. versionchanged:: 3.2
Support for unseekable files was added. Support for unseekable files was added.
.. versionchanged:: 3.2
The :meth:`peek` method was implemented.
.. function:: open(filename, mode='rb', compresslevel=9) .. function:: open(filename, mode='rb', compresslevel=9)

View File

@ -204,7 +204,10 @@ class GzipFile(io.BufferedIOBase):
return self.name return self.name
def __repr__(self): 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)) + '>' return '<gzip ' + s[1:-1] + ' ' + hex(id(self)) + '>'
def _init_write(self, filename): def _init_write(self, filename):
@ -336,6 +339,26 @@ class GzipFile(io.BufferedIOBase):
self.offset += size self.offset += size
return chunk 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): def _unread(self, buf):
self.extrasize = len(buf) + self.extrasize self.extrasize = len(buf) + self.extrasize
self.offset -= len(buf) self.offset -= len(buf)

View File

@ -286,6 +286,28 @@ class TestGzip(unittest.TestCase):
with gzip.GzipFile(fileobj=buf, mode="rb") as f: with gzip.GzipFile(fileobj=buf, mode="rb") as f:
self.assertEqual(f.read(), uncompressed) 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 # Testing compress/decompress shortcut functions
def test_compress(self): def test_compress(self):

View File

@ -76,6 +76,8 @@ Core and Builtins
Library Library
------- -------
- Issue #9962: GzipFile now has the peek() method.
- Issue #9090: When a socket with a timeout fails with EWOULDBLOCK or EAGAIN, - 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() 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 can incorrectly report a socket as ready for reading (for example, if it