Commit a3a1793c authored by Berker Peksag's avatar Berker Peksag

Issue #28227: gzip now supports pathlib

Patch by Ethan Furman.
parent e1f82f62
...@@ -56,6 +56,8 @@ The module defines the following items: ...@@ -56,6 +56,8 @@ The module defines the following items:
.. 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:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None) .. class:: GzipFile(filename=None, mode=None, compresslevel=9, fileobj=None, mtime=None)
...@@ -151,6 +153,9 @@ The module defines the following items: ...@@ -151,6 +153,9 @@ The module defines the following items:
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`.
.. function:: compress(data, compresslevel=9) .. function:: compress(data, compresslevel=9)
......
...@@ -49,7 +49,7 @@ def open(filename, mode="rb", compresslevel=9, ...@@ -49,7 +49,7 @@ def open(filename, mode="rb", compresslevel=9,
raise ValueError("Argument 'newline' not supported in binary mode") raise ValueError("Argument 'newline' not supported in binary mode")
gz_mode = mode.replace("t", "") gz_mode = mode.replace("t", "")
if isinstance(filename, (str, bytes)): if isinstance(filename, (str, bytes, os.PathLike)):
binary_file = GzipFile(filename, gz_mode, compresslevel) binary_file = GzipFile(filename, gz_mode, compresslevel)
elif hasattr(filename, "read") or hasattr(filename, "write"): elif hasattr(filename, "read") or hasattr(filename, "write"):
binary_file = GzipFile(None, gz_mode, compresslevel, filename) binary_file = GzipFile(None, gz_mode, compresslevel, filename)
...@@ -165,6 +165,8 @@ class GzipFile(_compression.BaseStream): ...@@ -165,6 +165,8 @@ class GzipFile(_compression.BaseStream):
filename = getattr(fileobj, 'name', '') filename = getattr(fileobj, 'name', '')
if not isinstance(filename, (str, bytes)): if not isinstance(filename, (str, bytes)):
filename = '' filename = ''
else:
filename = os.fspath(filename)
if mode is None: if mode is None:
mode = getattr(fileobj, 'mode', 'rb') mode = getattr(fileobj, 'mode', 'rb')
......
...@@ -5,6 +5,7 @@ import unittest ...@@ -5,6 +5,7 @@ import unittest
from test import support from test import support
from test.support import bigmemtest, _4G from test.support import bigmemtest, _4G
import os import os
import pathlib
import io import io
import struct import struct
import array import array
...@@ -67,6 +68,18 @@ class TestGzip(BaseTest): ...@@ -67,6 +68,18 @@ class TestGzip(BaseTest):
# Test multiple close() calls. # Test multiple close() calls.
f.close() f.close()
def test_write_read_with_pathlike_file(self):
filename = pathlib.Path(self.filename)
with gzip.GzipFile(filename, 'w') as f:
f.write(data1 * 50)
self.assertIsInstance(f.name, str)
with gzip.GzipFile(filename, 'a') as f:
f.write(data1)
with gzip.GzipFile(filename) as f:
d = f.read()
self.assertEqual(d, data1 * 51)
self.assertIsInstance(f.name, str)
# The following test_write_xy methods test that write accepts # The following test_write_xy methods test that write accepts
# the corresponding bytes-like object type as input # the corresponding bytes-like object type as input
# and that the data written equals bytes(xy) in all cases. # and that the data written equals bytes(xy) in all cases.
...@@ -521,6 +534,15 @@ class TestOpen(BaseTest): ...@@ -521,6 +534,15 @@ class TestOpen(BaseTest):
file_data = gzip.decompress(f.read()) file_data = gzip.decompress(f.read())
self.assertEqual(file_data, uncompressed) self.assertEqual(file_data, uncompressed)
def test_pathlike_file(self):
filename = pathlib.Path(self.filename)
with gzip.open(filename, "wb") as f:
f.write(data1 * 50)
with gzip.open(filename, "ab") as f:
f.write(data1)
with gzip.open(filename) as f:
self.assertEqual(f.read(), data1 * 51)
def test_implicit_binary_modes(self): def test_implicit_binary_modes(self):
# Test implicit binary modes (no "b" or "t" in mode string). # Test implicit binary modes (no "b" or "t" in mode string).
uncompressed = data1 * 50 uncompressed = data1 * 50
......
...@@ -46,6 +46,8 @@ Core and Builtins ...@@ -46,6 +46,8 @@ Core and Builtins
Library Library
------- -------
- Issue #28227: gzip now supports pathlib. Patch by Ethan Furman.
- Issue #27358: Optimized merging var-keyword arguments and improved error - Issue #27358: Optimized merging var-keyword arguments and improved error
message when pass a non-mapping as a var-keyword argument. message when pass a non-mapping as a var-keyword argument.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment