Issue #28229: Merge from 3.6

This commit is contained in:
Berker Peksag 2016-10-04 20:41:56 +03:00
commit d7f47ed28c
4 changed files with 47 additions and 13 deletions

View File

@ -39,8 +39,9 @@ Reading and writing compressed files
object`. object`.
The *filename* argument can be either an actual file name (given as a The *filename* argument can be either an actual file name (given as a
:class:`str` or :class:`bytes` object), in which case the named file is :class:`str`, :class:`bytes` or :term:`path-like object` object), in
opened, or it can be an existing file object to read from or write to. which case the named file is opened, or it can be an existing file object
to read from or write to.
The *mode* argument can be any of ``"r"``, ``"rb"``, ``"w"``, ``"wb"``, The *mode* argument can be any of ``"r"``, ``"rb"``, ``"w"``, ``"wb"``,
``"x"``, ``"xb"``, ``"a"`` or ``"ab"`` for binary mode, or ``"rt"``, ``"x"``, ``"xb"``, ``"a"`` or ``"ab"`` for binary mode, or ``"rt"``,
@ -64,6 +65,9 @@ Reading and writing compressed files
.. versionchanged:: 3.4 .. versionchanged:: 3.4
Added support for the ``"x"``, ``"xb"`` and ``"xt"`` modes. Added support for the ``"x"``, ``"xb"`` and ``"xt"`` modes.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
.. class:: LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None) .. class:: LZMAFile(filename=None, mode="r", \*, format=None, check=-1, preset=None, filters=None)
@ -71,9 +75,10 @@ Reading and writing compressed files
An :class:`LZMAFile` can wrap an already-open :term:`file object`, or operate An :class:`LZMAFile` can wrap an already-open :term:`file object`, or operate
directly on a named file. The *filename* argument specifies either the file directly on a named file. The *filename* argument specifies either the file
object to wrap, or the name of the file to open (as a :class:`str` or object to wrap, or the name of the file to open (as a :class:`str`,
:class:`bytes` object). When wrapping an existing file object, the wrapped :class:`bytes` or :term:`path-like object` object). When wrapping an
file will not be closed when the :class:`LZMAFile` is closed. existing file object, the wrapped file will not be closed when the
:class:`LZMAFile` is closed.
The *mode* argument can be either ``"r"`` for reading (default), ``"w"`` for The *mode* argument can be either ``"r"`` for reading (default), ``"w"`` for
overwriting, ``"x"`` for exclusive creation, or ``"a"`` for appending. These overwriting, ``"x"`` for exclusive creation, or ``"a"`` for appending. These
@ -118,6 +123,9 @@ Reading and writing compressed files
The :meth:`~io.BufferedIOBase.read` method now accepts an argument of The :meth:`~io.BufferedIOBase.read` method now accepts an argument of
``None``. ``None``.
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.
Compressing and decompressing data in memory Compressing and decompressing data in memory
-------------------------------------------- --------------------------------------------

View File

@ -23,6 +23,7 @@ __all__ = [
import builtins import builtins
import io import io
import os
from _lzma import * from _lzma import *
from _lzma import _encode_filter_properties, _decode_filter_properties from _lzma import _encode_filter_properties, _decode_filter_properties
import _compression import _compression
@ -49,9 +50,10 @@ class LZMAFile(_compression.BaseStream):
format=None, check=-1, preset=None, filters=None): format=None, check=-1, preset=None, filters=None):
"""Open an LZMA-compressed file in binary mode. """Open an LZMA-compressed file in binary mode.
filename can be either an actual file name (given as a str or filename can be either an actual file name (given as a str,
bytes object), in which case the named file is opened, or it can bytes, or PathLike object), in which case the named file is
be an existing file object to read from or write to. opened, or it can be an existing file object to read from or
write to.
mode can be "r" for reading (default), "w" for (over)writing, mode can be "r" for reading (default), "w" for (over)writing,
"x" for creating exclusively, or "a" for appending. These can "x" for creating exclusively, or "a" for appending. These can
@ -112,7 +114,7 @@ class LZMAFile(_compression.BaseStream):
else: else:
raise ValueError("Invalid mode: {!r}".format(mode)) raise ValueError("Invalid mode: {!r}".format(mode))
if isinstance(filename, (str, bytes)): if isinstance(filename, (str, bytes, os.PathLike)):
if "b" not in mode: if "b" not in mode:
mode += "b" mode += "b"
self._fp = builtins.open(filename, mode) self._fp = builtins.open(filename, mode)
@ -122,7 +124,7 @@ class LZMAFile(_compression.BaseStream):
self._fp = filename self._fp = filename
self._mode = mode_code self._mode = mode_code
else: else:
raise TypeError("filename must be a str or bytes object, or a file") raise TypeError("filename must be a str, bytes, file or PathLike object")
if self._mode == _MODE_READ: if self._mode == _MODE_READ:
raw = _compression.DecompressReader(self._fp, LZMADecompressor, raw = _compression.DecompressReader(self._fp, LZMADecompressor,
@ -263,9 +265,9 @@ def open(filename, mode="rb", *,
encoding=None, errors=None, newline=None): encoding=None, errors=None, newline=None):
"""Open an LZMA-compressed file in binary or text mode. """Open an LZMA-compressed file in binary or text mode.
filename can be either an actual file name (given as a str or bytes filename can be either an actual file name (given as a str, bytes,
object), in which case the named file is opened, or it can be an or PathLike object), in which case the named file is opened, or it
existing file object to read from or write to. can be an existing file object to read from or write to.
The mode argument can be "r", "rb" (default), "w", "wb", "x", "xb", The mode argument can be "r", "rb" (default), "w", "wb", "x", "xb",
"a", or "ab" for binary mode, or "rt", "wt", "xt", or "at" for text "a", or "ab" for binary mode, or "rt", "wt", "xt", or "at" for text

View File

@ -1,6 +1,7 @@
import _compression import _compression
from io import BytesIO, UnsupportedOperation, DEFAULT_BUFFER_SIZE from io import BytesIO, UnsupportedOperation, DEFAULT_BUFFER_SIZE
import os import os
import pathlib
import pickle import pickle
import random import random
import unittest import unittest
@ -488,6 +489,16 @@ class FileTestCase(unittest.TestCase):
with LZMAFile(BytesIO(), "a") as f: with LZMAFile(BytesIO(), "a") as f:
pass pass
def test_init_with_PathLike_filename(self):
filename = pathlib.Path(TESTFN)
with TempFile(filename, COMPRESSED_XZ):
with LZMAFile(filename) as f:
self.assertEqual(f.read(), INPUT)
with LZMAFile(filename, "a") as f:
f.write(INPUT)
with LZMAFile(filename) as f:
self.assertEqual(f.read(), INPUT * 2)
def test_init_with_filename(self): def test_init_with_filename(self):
with TempFile(TESTFN, COMPRESSED_XZ): with TempFile(TESTFN, COMPRESSED_XZ):
with LZMAFile(TESTFN) as f: with LZMAFile(TESTFN) as f:
@ -1180,6 +1191,17 @@ class OpenTestCase(unittest.TestCase):
with lzma.open(TESTFN, "rb") as f: with lzma.open(TESTFN, "rb") as f:
self.assertEqual(f.read(), INPUT * 2) self.assertEqual(f.read(), INPUT * 2)
def test_with_pathlike_filename(self):
filename = pathlib.Path(TESTFN)
with TempFile(filename):
with lzma.open(filename, "wb") as f:
f.write(INPUT)
with open(filename, "rb") as f:
file_data = lzma.decompress(f.read())
self.assertEqual(file_data, INPUT)
with lzma.open(filename, "rb") as f:
self.assertEqual(f.read(), INPUT)
def test_bad_params(self): def test_bad_params(self):
# Test invalid parameter combinations. # Test invalid parameter combinations.
with self.assertRaises(ValueError): with self.assertRaises(ValueError):

View File

@ -58,6 +58,8 @@ Core and Builtins
Library Library
------- -------
- Issue #28229: lzma module now supports pathlib.
- Issue #28321: Fixed writing non-BMP characters with binary format in plistlib. - Issue #28321: Fixed writing non-BMP characters with binary format in plistlib.
- Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman. - Issue #28225: bz2 module now supports pathlib. Initial patch by Ethan Furman.