Skip to content

gh-115961: Add name and mode attributes for compressed file-like objects #116036

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion Doc/library/bz2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ The :mod:`bz2` module contains:
and :meth:`~io.IOBase.truncate`.
Iteration and the :keyword:`with` statement are supported.

:class:`BZ2File` also provides the following methods:
:class:`BZ2File` also provides the following methods and attributes:

.. method:: peek([n])

Expand Down Expand Up @@ -148,6 +148,19 @@ The :mod:`bz2` module contains:

.. versionadded:: 3.3

.. attribute:: mode

``'rb'`` for reading and ``'wb'`` for writing.

.. versionadded:: 3.13

.. attribute:: name

The bzip2 file name. Equivalent to the :attr:`~io.FileIO.name`
attribute of the underlying :term:`file object`.

.. versionadded:: 3.13


.. versionchanged:: 3.1
Support for the :keyword:`with` statement was added.
Expand Down
15 changes: 11 additions & 4 deletions Doc/library/gzip.rst
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ The module defines the following items:

.. versionadded:: 3.2

.. attribute:: mode

``'rb'`` for reading and ``'wb'`` for writing.

.. versionchanged:: 3.13
In previous versions it was an integer ``1`` or ``2``.

.. attribute:: mtime

When decompressing, this attribute is set to the last timestamp in the most
Expand Down Expand Up @@ -168,14 +175,14 @@ The module defines the following items:
.. versionchanged:: 3.6
Accepts a :term:`path-like object`.

.. versionchanged:: 3.12
Remove the ``filename`` attribute, use the :attr:`~GzipFile.name`
attribute instead.

.. deprecated:: 3.9
Opening :class:`GzipFile` for writing without specifying the *mode*
argument is deprecated.

.. versionchanged:: 3.12
Remove the ``filename`` attribute, use the :attr:`~GzipFile.name`
attribute instead.


.. function:: compress(data, compresslevel=9, *, mtime=None)

Expand Down
16 changes: 15 additions & 1 deletion Doc/library/lzma.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Reading and writing compressed files
and :meth:`~io.IOBase.truncate`.
Iteration and the :keyword:`with` statement are supported.

The following method is also provided:
The following method and attributes are also provided:

.. method:: peek(size=-1)

Expand All @@ -117,6 +117,20 @@ Reading and writing compressed files
file object (e.g. if the :class:`LZMAFile` was constructed by passing a
file object for *filename*).

.. attribute:: mode

``'rb'`` for reading and ``'wb'`` for writing.

.. versionadded:: 3.13

.. attribute:: name

The lzma file name. Equivalent to the :attr:`~io.FileIO.name`
attribute of the underlying :term:`file object`.

.. versionadded:: 3.13


.. versionchanged:: 3.4
Added support for the ``"x"`` and ``"xb"`` modes.

Expand Down
4 changes: 4 additions & 0 deletions Doc/library/tarfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ be finalized; only the internally used file object will be closed. See the
.. versionchanged:: 3.3
Return an :class:`io.BufferedReader` object.

.. versionchanged:: 3.13
The returned :class:`io.BufferedReader` object has the :attr:`!mode`
attribute which is always equal to ``'rb'``.

.. attribute:: TarFile.errorlevel
:type: int

Expand Down
10 changes: 10 additions & 0 deletions Doc/library/zipfile.rst
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,10 @@ ZipFile Objects
attempting to read or write other files in the ZIP file will raise a
:exc:`ValueError`.

In both cases the file-like object has also attributes :attr:`!name`,
which is equivalent to the name of a file within the archive, and
:attr:`!mode`, which is ``'rb'`` or ``'wb'`` depending on the input mode.

When writing a file, if the file size is not known in advance but may exceed
2 GiB, pass ``force_zip64=True`` to ensure that the header format is
capable of supporting large files. If the file size is known in advance,
Expand All @@ -325,6 +329,12 @@ ZipFile Objects
Calling :meth:`.open` on a closed ZipFile will raise a :exc:`ValueError`.
Previously, a :exc:`RuntimeError` was raised.

.. versionchanged:: 3.13
Added attributes :attr:`!name` and :attr:`!mode` for the writeable
file-like object.
The value of the :attr:`!mode` attribute for the readable file-like
object was changed from ``'r'`` to ``'rb'``.


.. method:: ZipFile.extract(member, path=None, pwd=None)

Expand Down
11 changes: 11 additions & 0 deletions Doc/whatsnew/3.13.rst
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ Other Language Changes

(Contributed by Victor Stinner in :gh:`114570`.)

* Added :attr:`!name` and :attr:`!mode` attributes for compressed
and archived file-like objects in modules :mod:`bz2`, :mod:`lzma`,
:mod:`tarfile` and :mod:`zipfile`.
(Contributed by Serhiy Storchaka in :gh:`115961`.)

* Allow controlling Expat >=2.6.0 reparse deferral (:cve:`2023-52425`)
by adding five new methods:

Expand Down Expand Up @@ -1584,6 +1589,12 @@ Changes in the Python API
than directories only. Users may add a trailing slash to match only
directories.

* The value of the :attr:`!mode` attribute of :class:`gzip.GzipFile` was
changed from integer (``1`` or ``2``) to string (``'rb'`` or ``'wb'``).
The value of the :attr:`!mode` attribute of the readable file-like object
returned by :meth:`zipfile.ZipFile.open` was changed from ``'r'`` to ``'rb'``.
(Contributed by Serhiy Storchaka in :gh:`115961`.)

* :c:func:`!PyCode_GetFirstFree` is an unstable API now and has been renamed
to :c:func:`PyUnstable_Code_GetFirstFree`.
(Contributed by Bogdan Romanyuk in :gh:`115781`.)
Expand Down
18 changes: 13 additions & 5 deletions Lib/bz2.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
from _bz2 import BZ2Compressor, BZ2Decompressor


_MODE_CLOSED = 0
# Value 0 no longer used
_MODE_READ = 1
# Value 2 no longer used
_MODE_WRITE = 3
Expand Down Expand Up @@ -54,7 +54,7 @@ def __init__(self, filename, mode="r", *, compresslevel=9):
"""
self._fp = None
self._closefp = False
self._mode = _MODE_CLOSED
self._mode = None

if not (1 <= compresslevel <= 9):
raise ValueError("compresslevel must be between 1 and 9")
Expand Down Expand Up @@ -100,7 +100,7 @@ def close(self):
May be called more than once without error. Once the file is
closed, any other operation on it will raise a ValueError.
"""
if self._mode == _MODE_CLOSED:
if self.closed:
return
try:
if self._mode == _MODE_READ:
Expand All @@ -115,13 +115,21 @@ def close(self):
finally:
self._fp = None
self._closefp = False
self._mode = _MODE_CLOSED
self._buffer = None

@property
def closed(self):
"""True if this file is closed."""
return self._mode == _MODE_CLOSED
return self._fp is None

@property
def name(self):
self._check_not_closed()
return self._fp.name

@property
def mode(self):
return 'wb' if self._mode == _MODE_WRITE else 'rb'

def fileno(self):
"""Return the file descriptor for the underlying file."""
Expand Down
3 changes: 2 additions & 1 deletion Lib/gzip.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

FTEXT, FHCRC, FEXTRA, FNAME, FCOMMENT = 1, 2, 4, 8, 16

READ, WRITE = 1, 2
READ = 'rb'
WRITE = 'wb'

_COMPRESS_LEVEL_FAST = 1
_COMPRESS_LEVEL_TRADEOFF = 6
Expand Down
18 changes: 13 additions & 5 deletions Lib/lzma.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import _compression


_MODE_CLOSED = 0
# Value 0 no longer used
_MODE_READ = 1
# Value 2 no longer used
_MODE_WRITE = 3
Expand Down Expand Up @@ -92,7 +92,7 @@ def __init__(self, filename=None, mode="r", *,
"""
self._fp = None
self._closefp = False
self._mode = _MODE_CLOSED
self._mode = None

if mode in ("r", "rb"):
if check != -1:
Expand Down Expand Up @@ -137,7 +137,7 @@ def close(self):
May be called more than once without error. Once the file is
closed, any other operation on it will raise a ValueError.
"""
if self._mode == _MODE_CLOSED:
if self.closed:
return
try:
if self._mode == _MODE_READ:
Expand All @@ -153,12 +153,20 @@ def close(self):
finally:
self._fp = None
self._closefp = False
self._mode = _MODE_CLOSED

@property
def closed(self):
"""True if this file is closed."""
return self._mode == _MODE_CLOSED
return self._fp is None

@property
def name(self):
self._check_not_closed()
return self._fp.name

@property
def mode(self):
return 'wb' if self._mode == _MODE_WRITE else 'rb'

def fileno(self):
"""Return the file descriptor for the underlying file."""
Expand Down
4 changes: 4 additions & 0 deletions Lib/tarfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -636,6 +636,10 @@ def __init__(self, fileobj, offset, size, name, blockinfo=None):
def flush(self):
pass

@property
def mode(self):
return 'rb'

def readable(self):
return True

Expand Down
Loading
Loading