Skip to content

Commit 401c07f

Browse files
Merge branch 'main' into fix-issue-126349
2 parents 8487336 + 81376fe commit 401c07f

File tree

14 files changed

+504
-547
lines changed

14 files changed

+504
-547
lines changed

Doc/library/zipfile.rst

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,17 @@ The module defines the following items:
8484
formerly protected :attr:`!_compresslevel`. The older protected name
8585
continues to work as a property for backwards compatibility.
8686

87+
88+
.. method:: _for_archive(archive)
89+
90+
Resolve the date_time, compression attributes, and external attributes
91+
to suitable defaults as used by :meth:`ZipFile.writestr`.
92+
93+
Returns self for chaining.
94+
95+
.. versionadded:: 3.14
96+
97+
8798
.. function:: is_zipfile(filename)
8899

89100
Returns ``True`` if *filename* is a valid ZIP file based on its magic number,

Doc/whatsnew/3.14.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,14 @@ uuid
671671
in :rfc:`9562`.
672672
(Contributed by Bénédikt Tran in :gh:`89083`.)
673673

674+
zipinfo
675+
-------
676+
677+
* Added :func:`ZipInfo._for_archive <zipfile.ZipInfo._for_archive>`
678+
to resolve suitable defaults for a :class:`~zipfile.ZipInfo` object
679+
as used by :func:`ZipFile.writestr <zipfile.ZipFile.writestr>`.
680+
681+
(Contributed by Bénédikt Tran in :gh:`123424`.)
674682

675683
.. Add improved modules above alphabetically, not here at the end.
676684

Lib/pathlib/_abc.py

Lines changed: 4 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import posixpath
1717
from errno import EINVAL
1818
from glob import _GlobberBase, _no_recurse_symlinks
19-
from stat import S_ISDIR, S_ISLNK, S_ISREG
2019
from pathlib._os import copyfileobj
2120

2221

@@ -206,21 +205,6 @@ def __str__(self):
206205
passing to system calls."""
207206
raise NotImplementedError
208207

209-
def as_posix(self):
210-
"""Return the string representation of the path with forward (/)
211-
slashes."""
212-
return str(self).replace(self.parser.sep, '/')
213-
214-
@property
215-
def drive(self):
216-
"""The drive prefix (letter or UNC path), if any."""
217-
return self.parser.splitdrive(self.anchor)[0]
218-
219-
@property
220-
def root(self):
221-
"""The root of the path, if any."""
222-
return self.parser.splitdrive(self.anchor)[1]
223-
224208
@property
225209
def anchor(self):
226210
"""The concatenation of the drive and root, or ''."""
@@ -292,51 +276,6 @@ def with_suffix(self, suffix):
292276
else:
293277
return self.with_name(stem + suffix)
294278

295-
def relative_to(self, other, *, walk_up=False):
296-
"""Return the relative path to another path identified by the passed
297-
arguments. If the operation is not possible (because this is not
298-
related to the other path), raise ValueError.
299-
300-
The *walk_up* parameter controls whether `..` may be used to resolve
301-
the path.
302-
"""
303-
if not isinstance(other, PurePathBase):
304-
other = self.with_segments(other)
305-
anchor0, parts0 = _explode_path(self)
306-
anchor1, parts1 = _explode_path(other)
307-
if anchor0 != anchor1:
308-
raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors")
309-
while parts0 and parts1 and parts0[-1] == parts1[-1]:
310-
parts0.pop()
311-
parts1.pop()
312-
for part in parts1:
313-
if not part or part == '.':
314-
pass
315-
elif not walk_up:
316-
raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
317-
elif part == '..':
318-
raise ValueError(f"'..' segment in {str(other)!r} cannot be walked")
319-
else:
320-
parts0.append('..')
321-
return self.with_segments(*reversed(parts0))
322-
323-
def is_relative_to(self, other):
324-
"""Return True if the path is relative to another path or False.
325-
"""
326-
if not isinstance(other, PurePathBase):
327-
other = self.with_segments(other)
328-
anchor0, parts0 = _explode_path(self)
329-
anchor1, parts1 = _explode_path(other)
330-
if anchor0 != anchor1:
331-
return False
332-
while parts0 and parts1 and parts0[-1] == parts1[-1]:
333-
parts0.pop()
334-
parts1.pop()
335-
for part in parts1:
336-
if part and part != '.':
337-
return False
338-
return True
339-
340279
@property
341280
def parts(self):
342281
"""An object providing sequence-like access to the
@@ -388,11 +327,6 @@ def parents(self):
388327
parent = split(path)[0]
389328
return tuple(parents)
390329

391-
def is_absolute(self):
392-
"""True if the path is absolute (has both a root and, if applicable,
393-
a drive)."""
394-
return self.parser.isabs(str(self))
395-
396330
def match(self, path_pattern, *, case_sensitive=None):
397331
"""
398332
Return True if this path matches the given pattern. If the pattern is
@@ -450,55 +384,33 @@ class PathBase(PurePathBase):
450384
"""
451385
__slots__ = ()
452386

453-
def stat(self, *, follow_symlinks=True):
454-
"""
455-
Return the result of the stat() system call on this path, like
456-
os.stat() does.
457-
"""
458-
raise NotImplementedError
459-
460-
# Convenience functions for querying the stat results
461-
462387
def exists(self, *, follow_symlinks=True):
463388
"""
464389
Whether this path exists.
465390
466391
This method normally follows symlinks; to check whether a symlink exists,
467392
add the argument follow_symlinks=False.
468393
"""
469-
try:
470-
self.stat(follow_symlinks=follow_symlinks)
471-
except (OSError, ValueError):
472-
return False
473-
return True
394+
raise NotImplementedError
474395

475396
def is_dir(self, *, follow_symlinks=True):
476397
"""
477398
Whether this path is a directory.
478399
"""
479-
try:
480-
return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode)
481-
except (OSError, ValueError):
482-
return False
400+
raise NotImplementedError
483401

484402
def is_file(self, *, follow_symlinks=True):
485403
"""
486404
Whether this path is a regular file (also True for symlinks pointing
487405
to regular files).
488406
"""
489-
try:
490-
return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode)
491-
except (OSError, ValueError):
492-
return False
407+
raise NotImplementedError
493408

494409
def is_symlink(self):
495410
"""
496411
Whether this path is a symbolic link.
497412
"""
498-
try:
499-
return S_ISLNK(self.stat(follow_symlinks=False).st_mode)
500-
except (OSError, ValueError):
501-
return False
413+
raise NotImplementedError
502414

503415
def open(self, mode='r', buffering=-1, encoding=None,
504416
errors=None, newline=None):

Lib/pathlib/_local.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from errno import *
88
from glob import _StringGlobber, _no_recurse_symlinks
99
from itertools import chain
10-
from stat import S_IMODE, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
10+
from stat import S_IMODE, S_ISDIR, S_ISREG, S_ISSOCK, S_ISBLK, S_ISCHR, S_ISFIFO
1111
from _collections_abc import Sequence
1212

1313
try:
@@ -437,6 +437,11 @@ def _parse_pattern(cls, pattern):
437437
parts.append('')
438438
return parts
439439

440+
def as_posix(self):
441+
"""Return the string representation of the path with forward (/)
442+
slashes."""
443+
return str(self).replace(self.parser.sep, '/')
444+
440445
@property
441446
def _raw_path(self):
442447
paths = self._raw_paths
@@ -725,7 +730,10 @@ def is_dir(self, *, follow_symlinks=True):
725730
"""
726731
if follow_symlinks:
727732
return os.path.isdir(self)
728-
return PathBase.is_dir(self, follow_symlinks=follow_symlinks)
733+
try:
734+
return S_ISDIR(self.stat(follow_symlinks=follow_symlinks).st_mode)
735+
except (OSError, ValueError):
736+
return False
729737

730738
def is_file(self, *, follow_symlinks=True):
731739
"""
@@ -734,7 +742,10 @@ def is_file(self, *, follow_symlinks=True):
734742
"""
735743
if follow_symlinks:
736744
return os.path.isfile(self)
737-
return PathBase.is_file(self, follow_symlinks=follow_symlinks)
745+
try:
746+
return S_ISREG(self.stat(follow_symlinks=follow_symlinks).st_mode)
747+
except (OSError, ValueError):
748+
return False
738749

739750
def is_mount(self):
740751
"""

Lib/pathlib/_types.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,5 @@ class Parser(Protocol):
1515

1616
sep: str
1717
def split(self, path: str) -> tuple[str, str]: ...
18-
def splitdrive(self, path: str) -> tuple[str, str]: ...
1918
def splitext(self, path: str) -> tuple[str, str]: ...
2019
def normcase(self, path: str) -> str: ...
21-
def isabs(self, path: str) -> bool: ...

0 commit comments

Comments
 (0)