Skip to content

Commit

Permalink
Apply changes from python/cpython@f912e5a2f6
Browse files Browse the repository at this point in the history
  • Loading branch information
jaraco committed May 28, 2024
1 parent 3ad87d8 commit 5e21839
Show file tree
Hide file tree
Showing 2 changed files with 148 additions and 73 deletions.
95 changes: 60 additions & 35 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 Expand Up @@ -872,7 +876,7 @@ class TarInfo(object):
pax_headers = ('A dictionary containing key-value pairs of an '
'associated pax extended header.'),
sparse = 'Sparse member information.',
tarfile = None,
_tarfile = None,
_sparse_structs = None,
_link_target = None,
)
Expand Down Expand Up @@ -901,6 +905,24 @@ def __init__(self, name=""):
self.sparse = None # sparse member information
self.pax_headers = {} # pax header information

@property
def tarfile(self):
import warnings
warnings.warn(
'The undocumented "tarfile" attribute of TarInfo objects '
+ 'is deprecated and will be removed in Python 3.16',
DeprecationWarning, stacklevel=2)
return self._tarfile

@tarfile.setter
def tarfile(self, tarfile):
import warnings
warnings.warn(
'The undocumented "tarfile" attribute of TarInfo objects '
+ 'is deprecated and will be removed in Python 3.16',
DeprecationWarning, stacklevel=2)
self._tarfile = tarfile

@property
def path(self):
'In pax headers, "name" is called "path".'
Expand Down Expand Up @@ -1195,7 +1217,7 @@ def _create_pax_generic_header(cls, pax_headers, type, encoding):
for keyword, value in pax_headers.items():
keyword = keyword.encode("utf-8")
if binary:
# Try to restore the original byte representation of `value'.
# Try to restore the original byte representation of 'value'.
# Needless to say, that the encoding must match the string.
value = value.encode(encoding, "surrogateescape")
else:
Expand Down Expand Up @@ -1641,13 +1663,13 @@ def __init__(self, name=None, mode="r", fileobj=None, format=None,
tarinfo=None, dereference=None, ignore_zeros=None, encoding=None,
errors="surrogateescape", pax_headers=None, debug=None,
errorlevel=None, copybufsize=None, stream=False):
"""Open an (uncompressed) tar archive `name'. `mode' is either 'r' to
"""Open an (uncompressed) tar archive 'name'. 'mode' is either 'r' to
read from an existing archive, 'a' to append data to an existing
file or 'w' to create a new file overwriting an existing one. `mode'
file or 'w' to create a new file overwriting an existing one. 'mode'
defaults to 'r'.
If `fileobj' is given, it is used for reading or writing data. If it
can be determined, `mode' is overridden by `fileobj's mode.
`fileobj' is not closed, when TarFile is closed.
If 'fileobj' is given, it is used for reading or writing data. If it
can be determined, 'mode' is overridden by 'fileobj's mode.
'fileobj' is not closed, when TarFile is closed.
"""
modes = {"r": "rb", "a": "r+b", "w": "wb", "x": "xb"}
if mode not in modes:
Expand Down Expand Up @@ -1976,7 +1998,7 @@ def close(self):
self.fileobj.close()

def getmember(self, name):
"""Return a TarInfo object for member `name'. If `name' can not be
"""Return a TarInfo object for member 'name'. If 'name' can not be
found in the archive, KeyError is raised. If a member occurs more
than once in the archive, its last occurrence is assumed to be the
most up-to-date version.
Expand Down Expand Up @@ -2004,9 +2026,9 @@ def getnames(self):

def gettarinfo(self, name=None, arcname=None, fileobj=None):
"""Create a TarInfo object from the result of os.stat or equivalent
on an existing file. The file is either named by `name', or
specified as a file object `fileobj' with a file descriptor. If
given, `arcname' specifies an alternative name for the file in the
on an existing file. The file is either named by 'name', or
specified as a file object 'fileobj' with a file descriptor. If
given, 'arcname' specifies an alternative name for the file in the
archive, otherwise, the name is taken from the 'name' attribute of
'fileobj', or the 'name' argument. The name should be a text
string.
Expand All @@ -2030,7 +2052,7 @@ def gettarinfo(self, name=None, arcname=None, fileobj=None):
# Now, fill the TarInfo object with
# information specific for the file.
tarinfo = self.tarinfo()
tarinfo.tarfile = self # Not needed
tarinfo._tarfile = self # To be removed in 3.16.

# Use os.stat or os.lstat, depending on if symlinks shall be resolved.
if fileobj is None:
Expand Down Expand Up @@ -2102,9 +2124,9 @@ def gettarinfo(self, name=None, arcname=None, fileobj=None):
return tarinfo

def list(self, verbose=True, *, members=None):
"""Print a table of contents to sys.stdout. If `verbose' is False, only
the names of the members are printed. If it is True, an `ls -l'-like
output is produced. `members' is optional and must be a subset of the
"""Print a table of contents to sys.stdout. If 'verbose' is False, only
the names of the members are printed. If it is True, an 'ls -l'-like
output is produced. 'members' is optional and must be a subset of the
list returned by getmembers().
"""
# Convert tarinfo type to stat type.
Expand Down Expand Up @@ -2145,11 +2167,11 @@ def list(self, verbose=True, *, members=None):
print()

def add(self, name, arcname=None, recursive=True, *, filter=None):
"""Add the file `name' to the archive. `name' may be any type of file
(directory, fifo, symbolic link, etc.). If given, `arcname'
"""Add the file 'name' to the archive. 'name' may be any type of file
(directory, fifo, symbolic link, etc.). If given, 'arcname'
specifies an alternative name for the file in the archive.
Directories are added recursively by default. This can be avoided by
setting `recursive' to False. `filter' is a function
setting 'recursive' to False. 'filter' is a function
that expects a TarInfo object argument and returns the changed
TarInfo object, if it returns None the TarInfo object will be
excluded from the archive.
Expand Down Expand Up @@ -2196,13 +2218,16 @@ def add(self, name, arcname=None, recursive=True, *, filter=None):
self.addfile(tarinfo)

def addfile(self, tarinfo, fileobj=None):
"""Add the TarInfo object `tarinfo' to the archive. If `fileobj' is
given, it should be a binary file, and tarinfo.size bytes are read
from it and added to the archive. You can create TarInfo objects
directly, or by using gettarinfo().
"""Add the TarInfo object 'tarinfo' to the archive. If 'tarinfo' represents
a non zero-size regular file, the 'fileobj' argument should be a binary file,
and tarinfo.size bytes are read from it and added to the archive.
You can create TarInfo objects directly, or by using gettarinfo().
"""
self._check("awx")

if fileobj is None and tarinfo.isreg() and tarinfo.size != 0:
raise ValueError("fileobj not provided for non zero-size regular file")

tarinfo = copy.copy(tarinfo)

buf = tarinfo.tobuf(self.format, self.encoding, self.errors)
Expand All @@ -2229,7 +2254,7 @@ def _get_filter_function(self, filter):
'Python 3.14 will, by default, filter extracted tar '
+ 'archives and reject files or modify their metadata. '
+ 'Use the filter argument to control this behavior.',
DeprecationWarning)
DeprecationWarning, stacklevel=3)
return fully_trusted_filter
if isinstance(filter, str):
raise TypeError(
Expand All @@ -2248,12 +2273,12 @@ def extractall(self, path=".", members=None, *, numeric_owner=False,
filter=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers(). If `numeric_owner` is True, only
directories afterwards. 'path' specifies a different directory
to extract to. 'members' is optional and must be a subset of the
list returned by getmembers(). If 'numeric_owner' is True, only
the numbers for user/group names are used and not the names.
The `filter` function will be called on each member just
The 'filter' function will be called on each member just
before extraction.
It can return a changed TarInfo or None to skip the member.
String names of common filters are accepted.
Expand Down Expand Up @@ -2293,13 +2318,13 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False,
filter=None):
"""Extract a member from the archive to the current working directory,
using its full name. Its file information is extracted as accurately
as possible. `member' may be a filename or a TarInfo object. You can
specify a different directory using `path'. File attributes (owner,
mtime, mode) are set unless `set_attrs' is False. If `numeric_owner`
as possible. 'member' may be a filename or a TarInfo object. You can
specify a different directory using 'path'. File attributes (owner,
mtime, mode) are set unless 'set_attrs' is False. If 'numeric_owner'
is True, only the numbers for user/group names are used and not
the names.
The `filter` function will be called before extraction.
The 'filter' function will be called before extraction.
It can return a changed TarInfo or None to skip the member.
String names of common filters are accepted.
"""
Expand Down Expand Up @@ -2364,10 +2389,10 @@ def _handle_fatal_error(self, e):
self._dbg(1, "tarfile: %s %s" % (type(e).__name__, e))

def extractfile(self, member):
"""Extract a member from the archive as a file object. `member' may be
a filename or a TarInfo object. If `member' is a regular file or
"""Extract a member from the archive as a file object. 'member' may be
a filename or a TarInfo object. If 'member' is a regular file or
a link, an io.BufferedReader object is returned. For all other
existing members, None is returned. If `member' does not appear
existing members, None is returned. If 'member' does not appear
in the archive, KeyError is raised.
"""
self._check("r")
Expand Down Expand Up @@ -2565,7 +2590,7 @@ def chown(self, tarinfo, targetpath, numeric_owner):
else:
os.chown(targetpath, u, g)
except (OSError, OverflowError) as e:
# OverflowError can be raised if an ID doesn't fit in `id_t`
# OverflowError can be raised if an ID doesn't fit in 'id_t'
raise ExtractError("could not change owner") from e

def chmod(self, tarinfo, targetpath):
Expand Down
Loading

0 comments on commit 5e21839

Please sign in to comment.