Add fileobj support to gzip.open().
This commit is contained in:
parent
d7b7c7472b
commit
68721019ef
|
@ -14,10 +14,10 @@ like the GNU programs :program:`gzip` and :program:`gunzip` would.
|
||||||
The data compression is provided by the :mod:`zlib` module.
|
The data compression is provided by the :mod:`zlib` module.
|
||||||
|
|
||||||
The :mod:`gzip` module provides the :class:`GzipFile` class, as well as the
|
The :mod:`gzip` module provides the :class:`GzipFile` class, as well as the
|
||||||
:func:`gzip.open`, :func:`compress` and :func:`decompress` convenience
|
:func:`.open`, :func:`compress` and :func:`decompress` convenience functions.
|
||||||
functions. The :class:`GzipFile` class reads and writes :program:`gzip`\ -format
|
The :class:`GzipFile` class reads and writes :program:`gzip`\ -format files,
|
||||||
files, automatically compressing or decompressing the data so that it looks like
|
automatically compressing or decompressing the data so that it looks like an
|
||||||
an ordinary :term:`file object`.
|
ordinary :term:`file object`.
|
||||||
|
|
||||||
Note that additional file formats which can be decompressed by the
|
Note that additional file formats which can be decompressed by the
|
||||||
:program:`gzip` and :program:`gunzip` programs, such as those produced by
|
:program:`gzip` and :program:`gunzip` programs, such as those produced by
|
||||||
|
@ -28,9 +28,11 @@ The module defines the following items:
|
||||||
|
|
||||||
.. function:: open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None)
|
.. function:: open(filename, mode='rb', compresslevel=9, encoding=None, errors=None, newline=None)
|
||||||
|
|
||||||
Open *filename* as a gzip-compressed file in binary or text mode.
|
Open a gzip-compressed file in binary or text mode, returning a :term:`file
|
||||||
|
object`.
|
||||||
|
|
||||||
Returns a :term:`file object`.
|
The *filename* argument can be an actual filename (a :class:`str` or
|
||||||
|
:class:`bytes` object), or an existing file object to read from or write to.
|
||||||
|
|
||||||
The *mode* argument can be any of ``'r'``, ``'rb'``, ``'a'``, ``'ab'``,
|
The *mode* argument can be any of ``'r'``, ``'rb'``, ``'a'``, ``'ab'``,
|
||||||
``'w'``, or ``'wb'`` for binary mode, or ``'rt'``, ``'at'``, or ``'wt'`` for
|
``'w'``, or ``'wb'`` for binary mode, or ``'rt'``, ``'at'``, or ``'wt'`` for
|
||||||
|
@ -48,8 +50,8 @@ The module defines the following items:
|
||||||
handling behavior, and line ending(s).
|
handling behavior, and line ending(s).
|
||||||
|
|
||||||
.. versionchanged:: 3.3
|
.. versionchanged:: 3.3
|
||||||
Support for text mode was added, along with the *encoding*, *errors* and
|
Added support for *filename* being a file object, support for text mode,
|
||||||
*newline* arguments.
|
and the *encoding*, *errors* and *newline* arguments.
|
||||||
|
|
||||||
|
|
||||||
.. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
|
.. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
|
||||||
|
@ -75,7 +77,7 @@ The module defines the following items:
|
||||||
is the mode of *fileobj* if discernible; otherwise, the default is ``'rb'``.
|
is the mode of *fileobj* if discernible; otherwise, the default is ``'rb'``.
|
||||||
|
|
||||||
Note that the file is always opened in binary mode. To open a compressed file
|
Note that the file is always opened in binary mode. To open a compressed file
|
||||||
in text mode, use :func:`gzip.open` (or wrap your :class:`GzipFile` with an
|
in text mode, use :func:`.open` (or wrap your :class:`GzipFile` with an
|
||||||
:class:`io.TextIOWrapper`).
|
:class:`io.TextIOWrapper`).
|
||||||
|
|
||||||
The *compresslevel* argument is an integer from ``1`` to ``9`` controlling the
|
The *compresslevel* argument is an integer from ``1`` to ``9`` controlling the
|
||||||
|
|
13
Lib/gzip.py
13
Lib/gzip.py
|
@ -20,6 +20,9 @@ def open(filename, mode="rb", compresslevel=9,
|
||||||
encoding=None, errors=None, newline=None):
|
encoding=None, errors=None, newline=None):
|
||||||
"""Open a gzip-compressed file in binary or text mode.
|
"""Open a gzip-compressed file in binary or text mode.
|
||||||
|
|
||||||
|
The filename argument can be an actual filename (a str or bytes object), or
|
||||||
|
an existing file object to read from or write to.
|
||||||
|
|
||||||
The mode argument can be "r", "rb", "w", "wb", "a" or "ab" for binary mode,
|
The mode argument can be "r", "rb", "w", "wb", "a" or "ab" for binary mode,
|
||||||
or "rt", "wt" or "at" for text mode. The default mode is "rb", and the
|
or "rt", "wt" or "at" for text mode. The default mode is "rb", and the
|
||||||
default compresslevel is 9.
|
default compresslevel is 9.
|
||||||
|
@ -43,7 +46,15 @@ def open(filename, mode="rb", compresslevel=9,
|
||||||
raise ValueError("Argument 'errors' not supported in binary mode")
|
raise ValueError("Argument 'errors' not supported in binary mode")
|
||||||
if newline is not None:
|
if newline is not None:
|
||||||
raise ValueError("Argument 'newline' not supported in binary mode")
|
raise ValueError("Argument 'newline' not supported in binary mode")
|
||||||
binary_file = GzipFile(filename, mode.replace("t", ""), compresslevel)
|
|
||||||
|
gz_mode = mode.replace("t", "")
|
||||||
|
if isinstance(filename, (str, bytes)):
|
||||||
|
binary_file = GzipFile(filename, gz_mode, compresslevel)
|
||||||
|
elif hasattr(filename, "read") or hasattr(filename, "write"):
|
||||||
|
binary_file = GzipFile(None, gz_mode, compresslevel, filename)
|
||||||
|
else:
|
||||||
|
raise TypeError("filename must be a str or bytes object, or a file")
|
||||||
|
|
||||||
if "t" in mode:
|
if "t" in mode:
|
||||||
return io.TextIOWrapper(binary_file, encoding, errors, newline)
|
return io.TextIOWrapper(binary_file, encoding, errors, newline)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -424,8 +424,21 @@ class TestOpen(BaseTest):
|
||||||
file_data = gzip.decompress(f.read()).decode("ascii")
|
file_data = gzip.decompress(f.read()).decode("ascii")
|
||||||
self.assertEqual(file_data, uncompressed_raw * 2)
|
self.assertEqual(file_data, uncompressed_raw * 2)
|
||||||
|
|
||||||
|
def test_fileobj(self):
|
||||||
|
uncompressed_bytes = data1 * 50
|
||||||
|
uncompressed_str = uncompressed_bytes.decode("ascii")
|
||||||
|
compressed = gzip.compress(uncompressed_bytes)
|
||||||
|
with gzip.open(io.BytesIO(compressed), "r") as f:
|
||||||
|
self.assertEqual(f.read(), uncompressed_bytes)
|
||||||
|
with gzip.open(io.BytesIO(compressed), "rb") as f:
|
||||||
|
self.assertEqual(f.read(), uncompressed_bytes)
|
||||||
|
with gzip.open(io.BytesIO(compressed), "rt") as f:
|
||||||
|
self.assertEqual(f.read(), uncompressed_str)
|
||||||
|
|
||||||
def test_bad_params(self):
|
def test_bad_params(self):
|
||||||
# Test invalid parameter combinations.
|
# Test invalid parameter combinations.
|
||||||
|
with self.assertRaises(TypeError):
|
||||||
|
gzip.open(123.456)
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
gzip.open(self.filename, "wbt")
|
gzip.open(self.filename, "wbt")
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
|
|
|
@ -15,6 +15,8 @@ Core and Builtins
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- gzip.open() now accepts file objects as well as filenames.
|
||||||
|
|
||||||
- Issue #14992: os.makedirs(path, exist_ok=True) would raise an OSError
|
- Issue #14992: os.makedirs(path, exist_ok=True) would raise an OSError
|
||||||
when the path existed and had the S_ISGID mode bit set when it was
|
when the path existed and had the S_ISGID mode bit set when it was
|
||||||
not explicitly asked for. This is no longer an exception as mkdir
|
not explicitly asked for. This is no longer an exception as mkdir
|
||||||
|
|
Loading…
Reference in New Issue