Update Windows Python3 prebuilt
Fusion2: http://fusion2/e1653ce5-a00b-4501-8f0f-1cb270563905
GCS path: gs://ndk-kokoro-release-artifacts/prod/ndk/python3/windows_release/4/20220830-004242
Prebuilt updated using: ndk/scripts/update_kokoro_prebuilts.py
Test: Treehugger, Kokoro presubmit
Bug: 244197859
Change-Id: I7e3cb5b8add31fd59e4085dba550c6fb436f1ed8
diff --git a/Lib/zipfile.py b/Lib/zipfile.py
index 816f858..67cfdfb 100644
--- a/Lib/zipfile.py
+++ b/Lib/zipfile.py
@@ -16,6 +16,7 @@
import threading
import time
import contextlib
+import pathlib
try:
import zlib # We may need its compression method
@@ -1120,8 +1121,15 @@
def write(self, data):
if self.closed:
raise ValueError('I/O operation on closed file.')
- nbytes = len(data)
+
+ # Accept any data that supports the buffer protocol
+ if isinstance(data, (bytes, bytearray)):
+ nbytes = len(data)
+ else:
+ data = memoryview(data)
+ nbytes = data.nbytes
self._file_size += nbytes
+
self._crc = crc32(data, self._crc)
if self._compressor:
data = self._compressor.compress(data)
@@ -2197,13 +2205,12 @@
if not isinstance(source, ZipFile):
return cls(source)
- # Only allow for FastPath when supplied zipfile is read-only
+ # Only allow for FastLookup when supplied zipfile is read-only
if 'r' not in source.mode:
cls = CompleteDirs
- res = cls.__new__(cls)
- vars(res).update(vars(source))
- return res
+ source.__class__ = cls
+ return source
class FastLookup(CompleteDirs):
@@ -2211,6 +2218,7 @@
ZipFile subclass to ensure implicit
dirs exist and are resolved rapidly.
"""
+
def namelist(self):
with contextlib.suppress(AttributeError):
return self.__names
@@ -2242,7 +2250,7 @@
>>> zf.writestr('a.txt', 'content of a')
>>> zf.writestr('b/c.txt', 'content of c')
>>> zf.writestr('b/d/e.txt', 'content of e')
- >>> zf.filename = 'abcde.zip'
+ >>> zf.filename = 'mem/abcde.zip'
Path accepts the zipfile object itself or a filename
@@ -2254,9 +2262,9 @@
>>> a, b = root.iterdir()
>>> a
- Path('abcde.zip', 'a.txt')
+ Path('mem/abcde.zip', 'a.txt')
>>> b
- Path('abcde.zip', 'b/')
+ Path('mem/abcde.zip', 'b/')
name property:
@@ -2267,7 +2275,7 @@
>>> c = b / 'c.txt'
>>> c
- Path('abcde.zip', 'b/c.txt')
+ Path('mem/abcde.zip', 'b/c.txt')
>>> c.name
'c.txt'
@@ -2285,36 +2293,68 @@
Coercion to string:
- >>> str(c)
- 'abcde.zip/b/c.txt'
+ >>> import os
+ >>> str(c).replace(os.sep, posixpath.sep)
+ 'mem/abcde.zip/b/c.txt'
+
+ At the root, ``name``, ``filename``, and ``parent``
+ resolve to the zipfile. Note these attributes are not
+ valid and will raise a ``ValueError`` if the zipfile
+ has no filename.
+
+ >>> root.name
+ 'abcde.zip'
+ >>> str(root.filename).replace(os.sep, posixpath.sep)
+ 'mem/abcde.zip'
+ >>> str(root.parent)
+ 'mem'
"""
__repr = "{self.__class__.__name__}({self.root.filename!r}, {self.at!r})"
def __init__(self, root, at=""):
+ """
+ Construct a Path from a ZipFile or filename.
+
+ Note: When the source is an existing ZipFile object,
+ its type (__class__) will be mutated to a
+ specialized type. If the caller wishes to retain the
+ original type, the caller should either create a
+ separate ZipFile object or pass a filename.
+ """
self.root = FastLookup.make(root)
self.at = at
- def open(self, mode='r', *args, **kwargs):
+ def open(self, mode='r', *args, pwd=None, **kwargs):
"""
Open this entry as text or binary following the semantics
of ``pathlib.Path.open()`` by passing arguments through
to io.TextIOWrapper().
"""
- pwd = kwargs.pop('pwd', None)
+ if self.is_dir():
+ raise IsADirectoryError(self)
zip_mode = mode[0]
+ if not self.exists() and zip_mode == 'r':
+ raise FileNotFoundError(self)
stream = self.root.open(self.at, zip_mode, pwd=pwd)
if 'b' in mode:
if args or kwargs:
raise ValueError("encoding args invalid for binary operation")
return stream
+ else:
+ kwargs["encoding"] = io.text_encoding(kwargs.get("encoding"))
return io.TextIOWrapper(stream, *args, **kwargs)
@property
def name(self):
- return posixpath.basename(self.at.rstrip("/"))
+ return pathlib.Path(self.at).name or self.filename.name
+
+ @property
+ def filename(self):
+ return pathlib.Path(self.root.filename).joinpath(self.at)
def read_text(self, *args, **kwargs):
+ kwargs["encoding"] = io.text_encoding(kwargs.get("encoding"))
with self.open('r', *args, **kwargs) as strm:
return strm.read()
@@ -2326,13 +2366,13 @@
return posixpath.dirname(path.at.rstrip("/")) == self.at.rstrip("/")
def _next(self, at):
- return Path(self.root, at)
+ return self.__class__(self.root, at)
def is_dir(self):
return not self.at or self.at.endswith("/")
def is_file(self):
- return not self.is_dir()
+ return self.exists() and not self.is_dir()
def exists(self):
return self.at in self.root._name_set()
@@ -2349,14 +2389,16 @@
def __repr__(self):
return self.__repr.format(self=self)
- def joinpath(self, add):
- next = posixpath.join(self.at, add)
+ def joinpath(self, *other):
+ next = posixpath.join(self.at, *other)
return self._next(self.root.resolve_dir(next))
__truediv__ = joinpath
@property
def parent(self):
+ if not self.at:
+ return self.filename.parent
parent_at = posixpath.dirname(self.at.rstrip('/'))
if parent_at:
parent_at += '/'