From c2505eb792baf4c159854d3be4a98886288835e6 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sat, 8 Jun 2024 16:32:35 -0500 Subject: [PATCH 01/16] chore: Accurate overloads for `ZipFile.__init__` --- stdlib/zipfile/__init__.pyi | 61 ++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index b61e07f8b90d..db290bd70168 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -94,6 +94,20 @@ class ZipExtFile(io.BufferedIOBase): class _Writer(Protocol): def write(self, s: str, /) -> object: ... +class _ZipReadFile(Protocol): + def seek(self, offset: int, whence: int = 0) -> int: ... + def read(self, n: int | None = -1) -> bytes: ... + +class _ZipTellable(Protocol): + def tell(self) -> int: ... + +class _ZipSeekTellable(_ZipTellable): + def seek(self, offset: int, whence: int = 0) -> int: ... + +class _ZipWritable(_Writer): + def flush(self) -> None: ... + def close(self) -> None: ... + class ZipFile: filename: str | None debug: int @@ -106,11 +120,13 @@ class ZipFile: compresslevel: int | None # undocumented mode: _ZipFileMode # undocumented pwd: bytes | None # undocumented + # metadata_encoding is new in 3.11 if sys.version_info >= (3, 11): + # metadata_encoding is only allowed for read mode @overload def __init__( self, - file: StrPath | IO[bytes], + file: StrPath | _ZipReadFile, mode: Literal["r"] = "r", compression: int = 0, allowZip64: bool = True, @@ -122,8 +138,20 @@ class ZipFile: @overload def __init__( self, - file: StrPath | IO[bytes], - mode: _ZipFileMode = "r", + file: StrPath | _ZipTellable | _ZipWritable, + mode: Literal["w", "x"] = ..., + compression: int = 0, + allowZip64: bool = True, + compresslevel: int | None = None, + *, + strict_timestamps: bool = True, + metadata_encoding: None = None, + ) -> None: ... + @overload + def __init__( + self, + file: StrPath | _ZipReadFile | _ZipSeekTellable, + mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, compresslevel: int | None = None, @@ -132,10 +160,33 @@ class ZipFile: metadata_encoding: None = None, ) -> None: ... else: + @overload + def __init__( + self, + file: StrPath | _ZipReadFile, + mode: Literal["r"] = "r", + compression: int = 0, + allowZip64: bool = True, + compresslevel: int | None = None, + *, + strict_timestamps: bool = True, + ) -> None: ... + @overload + def __init__( + self, + file: StrPath | _ZipTellable | _ZipWritable, + mode: Literal["w", "x"] = ..., + compression: int = 0, + allowZip64: bool = True, + compresslevel: int | None = None, + *, + strict_timestamps: bool = True, + ) -> None: ... + @overload def __init__( self, - file: StrPath | IO[bytes], - mode: _ZipFileMode = "r", + file: StrPath | _ZipReadFile | _ZipSeekTellable, + mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, compresslevel: int | None = None, From 6eafa4e9c7581836a68eafc2afef29e4148cffea Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sat, 8 Jun 2024 16:35:10 -0500 Subject: [PATCH 02/16] Tweak --- stdlib/zipfile/__init__.pyi | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index db290bd70168..137d66096513 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -122,6 +122,18 @@ class ZipFile: pwd: bytes | None # undocumented # metadata_encoding is new in 3.11 if sys.version_info >= (3, 11): + @overload + def __init__( + self, + file: StrPath | IO[bytes], + mode: _ZipFileMode = "r", + compression: int = 0, + allowZip64: bool = True, + compresslevel: int | None = None, + *, + strict_timestamps: bool = True, + metadata_encoding: str | None = None, + ) -> None: ... # metadata_encoding is only allowed for read mode @overload def __init__( @@ -160,6 +172,17 @@ class ZipFile: metadata_encoding: None = None, ) -> None: ... else: + @overload + def __init__( + self, + file: StrPath | IO[bytes], + mode: _ZipFileMode = "r", + compression: int = 0, + allowZip64: bool = True, + compresslevel: int | None = None, + *, + strict_timestamps: bool = True, + ) -> None: ... @overload def __init__( self, From 6bc28bde980b71020c83ee1930588227ffe140e4 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sat, 8 Jun 2024 16:40:16 -0500 Subject: [PATCH 03/16] Tweak --- stdlib/zipfile/__init__.pyi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index 137d66096513..fe9ec936a9ed 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -94,7 +94,7 @@ class ZipExtFile(io.BufferedIOBase): class _Writer(Protocol): def write(self, s: str, /) -> object: ... -class _ZipReadFile(Protocol): +class _ZipReadable(Protocol): def seek(self, offset: int, whence: int = 0) -> int: ... def read(self, n: int | None = -1) -> bytes: ... @@ -138,7 +138,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadFile, + file: StrPath | _ZipReadable, mode: Literal["r"] = "r", compression: int = 0, allowZip64: bool = True, @@ -162,7 +162,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadFile | _ZipSeekTellable, + file: StrPath | _ZipReadable | _ZipSeekTellable, mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, @@ -186,7 +186,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadFile, + file: StrPath | _ZipReadable, mode: Literal["r"] = "r", compression: int = 0, allowZip64: bool = True, @@ -208,7 +208,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadFile | _ZipSeekTellable, + file: StrPath | _ZipReadable | _ZipSeekTellable, mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, From 4cf07ab924f710fc7c656457036c7cabe93bc134 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:13:01 -0500 Subject: [PATCH 04/16] Add test --- stdlib/@tests/test_cases/check_zipfile.py | 119 ++++++++++++++++++++++ stdlib/zipfile/__init__.pyi | 8 +- 2 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 stdlib/@tests/test_cases/check_zipfile.py diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py new file mode 100644 index 000000000000..792cc0b80e09 --- /dev/null +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -0,0 +1,119 @@ +from typing import Literal +import zipfile +import pathlib + +import io + +p = pathlib.Path("test.zip") + + +class _CustomPathObj: + def __init__(self, path: str): + self.path = path + + def __fspath__(self): + return self.path + + +class NonPathObj: + def __init__(self, path: str): + self.path = path + + +class ReadableObj: + def seek(self, offset: int, whence: int = 0) -> int: + return 0 + + def read(self, n: int | None = -1) -> bytes: + return b"test" + + +class TellableObj: + def tell(self) -> int: + return 0 + + +class WriteableObj: + def close(self) -> None: + pass + + def write(self, b: bytes) -> int: + return len(b) + + def flush(self) -> None: + pass + + +class SeekTellObj: + def seek(self, offset: int, whence: int = 0) -> int: + return 0 + + def tell(self) -> int: + return 0 + + +def write_zip(mode: Literal["r", "w", "x", "a"]): + # Test any mode with `pathlib.Path` + with zipfile.ZipFile(p, mode) as z: + z.writestr("test.txt", "test") + + # Test any mode with `str` path + with zipfile.ZipFile("test.zip", mode) as z: + z.writestr("test.txt", "test") + + # Test any mode with `os.PathLike` object + with zipfile.ZipFile(_CustomPathObj("test.zip"), mode) as z: + z.writestr("test.txt", "test") + + # Non-PathLike object should raise an error + with zipfile.ZipFile(NonPathObj("test.zip"), mode) as z: # type: ignore + z.writestr("test.txt", "test") + + # IO[bytes] like-obj should work for any mode. + io_obj = io.BytesIO(b"This is a test") + with zipfile.ZipFile(io_obj, mode) as z: + z.writestr("test.txt", "test") + + # Readable object should not work for any mode. + with zipfile.ZipFile(ReadableObj(), mode) as z: # type: ignore + z.writestr("test.txt", "test") + + # Readable object should work for "r" mode. + with zipfile.ZipFile(ReadableObj(), "r") as z: + z.writestr("test.txt", "test") + + # Readable object should work for "a" mode. + with zipfile.ZipFile(ReadableObj(), "a") as z: + z.writestr("test.txt", "test") + + # Readable object should not work for "w" mode. + with zipfile.ZipFile(ReadableObj(), "w") as z: # type: ignore + z.writestr("test.txt", "test") + + # Tellable object should not work for any mode. + with zipfile.ZipFile(TellableObj(), mode) as z: # type: ignore + z.writestr("test.txt", "test") + + # Tellable object should work for "w" mode. + with zipfile.ZipFile(TellableObj(), "w") as z: + z.writestr("test.txt", "test") + + # Writeable object should not work for any mode. + with zipfile.ZipFile(WriteableObj(), mode) as z: # type: ignore + z.writestr("test.txt", "test") + + # Writeable object should work for "w" mode. + with zipfile.ZipFile(WriteableObj(), "w") as z: + z.writestr("test.txt", "test") + + # Seekable and Tellable object should not work for any mode. + with zipfile.ZipFile(SeekTellObj(), mode) as z: # type: ignore + z.writestr("test.txt", "test") + + # Seekable and Tellable object should work for "w" mode. + with zipfile.ZipFile(SeekTellObj(), "w") as z: + z.writestr("test.txt", "test") + + # Seekable and Tellable object should work for "a" mode. + with zipfile.ZipFile(SeekTellObj(), "a") as z: + z.writestr("test.txt", "test") diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index fe9ec936a9ed..3f28e07e6273 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -101,12 +101,14 @@ class _ZipReadable(Protocol): class _ZipTellable(Protocol): def tell(self) -> int: ... -class _ZipSeekTellable(_ZipTellable): +class _ZipSeekTellable(Protocol): def seek(self, offset: int, whence: int = 0) -> int: ... + def tell(self) -> int: ... -class _ZipWritable(_Writer): +class _ZipWritable(Protocol): def flush(self) -> None: ... def close(self) -> None: ... + def write(self, b: bytes) -> int: ... class ZipFile: filename: str | None @@ -145,7 +147,7 @@ class ZipFile: compresslevel: int | None = None, *, strict_timestamps: bool = True, - metadata_encoding: str | None, + metadata_encoding: str | None = None, ) -> None: ... @overload def __init__( From 7f75295778bdee375fe40f31e750da2a54b575dc Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:14:40 +0000 Subject: [PATCH 05/16] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/@tests/test_cases/check_zipfile.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index 792cc0b80e09..13a2d35d84dd 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -1,8 +1,9 @@ -from typing import Literal -import zipfile -import pathlib +from __future__ import annotations import io +import pathlib +import zipfile +from typing import Literal p = pathlib.Path("test.zip") From c9704b9f3163085985517277c14dd544d111367d Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:16:10 -0500 Subject: [PATCH 06/16] Tweaks --- stdlib/@tests/test_cases/check_zipfile.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index 13a2d35d84dd..967b02ab5e16 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -8,7 +8,12 @@ p = pathlib.Path("test.zip") -class _CustomPathObj: +### +# Tests for `zipfile.ZipFile` +### + + +class CustomPathObj: def __init__(self, path: str): self.path = path @@ -63,7 +68,7 @@ def write_zip(mode: Literal["r", "w", "x", "a"]): z.writestr("test.txt", "test") # Test any mode with `os.PathLike` object - with zipfile.ZipFile(_CustomPathObj("test.zip"), mode) as z: + with zipfile.ZipFile(CustomPathObj("test.zip"), mode) as z: z.writestr("test.txt", "test") # Non-PathLike object should raise an error From 377ce76e684f624d4551f220ada8810bc4bdfaf9 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:21:23 -0500 Subject: [PATCH 07/16] Tweak --- stdlib/zipfile/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index 3f28e07e6273..ef87766cc193 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -96,7 +96,7 @@ class _Writer(Protocol): class _ZipReadable(Protocol): def seek(self, offset: int, whence: int = 0) -> int: ... - def read(self, n: int | None = -1) -> bytes: ... + def read(self, n: int = -1) -> bytes: ... class _ZipTellable(Protocol): def tell(self) -> int: ... From 3af922f1b99697ea5edd7cedae0ba81366c1e3a5 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:29:47 -0500 Subject: [PATCH 08/16] Add missing annotations --- stdlib/@tests/test_cases/check_zipfile.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index 967b02ab5e16..d0c1e809c52e 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -5,24 +5,24 @@ import zipfile from typing import Literal -p = pathlib.Path("test.zip") - ### # Tests for `zipfile.ZipFile` ### +p = pathlib.Path("test.zip") + class CustomPathObj: - def __init__(self, path: str): + def __init__(self, path: str) -> None: self.path = path - def __fspath__(self): + def __fspath__(self) -> str: return self.path class NonPathObj: - def __init__(self, path: str): + def __init__(self, path: str) -> None: self.path = path From 0f7c9e0d651cca863a1e96cc00847b9e61043e87 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 9 Jun 2024 12:29:57 -0500 Subject: [PATCH 09/16] Missing annotation --- stdlib/@tests/test_cases/check_zipfile.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index d0c1e809c52e..f7ad33b744e9 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -58,7 +58,7 @@ def tell(self) -> int: return 0 -def write_zip(mode: Literal["r", "w", "x", "a"]): +def write_zip(mode: Literal["r", "w", "x", "a"]) -> None: # Test any mode with `pathlib.Path` with zipfile.ZipFile(p, mode) as z: z.writestr("test.txt", "test") From d82e36f633696a013863f889d5cb20b23905b648 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Sun, 9 Jun 2024 17:31:24 +0000 Subject: [PATCH 10/16] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/@tests/test_cases/check_zipfile.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index f7ad33b744e9..0d9bc1826e21 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -5,7 +5,6 @@ import zipfile from typing import Literal - ### # Tests for `zipfile.ZipFile` ### From 97a4a951cba60d162dace2278f62b31fcf6f3f6d Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sat, 22 Jun 2024 13:50:46 -0500 Subject: [PATCH 11/16] Use positional arguments --- stdlib/zipfile/__init__.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index ef87766cc193..877f817a0161 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -95,20 +95,20 @@ class _Writer(Protocol): def write(self, s: str, /) -> object: ... class _ZipReadable(Protocol): - def seek(self, offset: int, whence: int = 0) -> int: ... - def read(self, n: int = -1) -> bytes: ... + def seek(self, offset: int, whence: int = 0, /) -> int: ... + def read(self, n: int = -1, /) -> bytes: ... class _ZipTellable(Protocol): def tell(self) -> int: ... class _ZipSeekTellable(Protocol): - def seek(self, offset: int, whence: int = 0) -> int: ... + def seek(self, offset: int, whence: int = 0, /) -> int: ... def tell(self) -> int: ... class _ZipWritable(Protocol): def flush(self) -> None: ... def close(self) -> None: ... - def write(self, b: bytes) -> int: ... + def write(self, b: bytes, /) -> int: ... class ZipFile: filename: str | None From 0b52c6a446d454e51a5c6a9596a45d6ab78ca6d1 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:16:38 -0500 Subject: [PATCH 12/16] Address feedback --- stdlib/zipfile/__init__.pyi | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index 877f817a0161..aadcec81dd1b 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -101,9 +101,7 @@ class _ZipReadable(Protocol): class _ZipTellable(Protocol): def tell(self) -> int: ... -class _ZipSeekTellable(Protocol): - def seek(self, offset: int, whence: int = 0, /) -> int: ... - def tell(self) -> int: ... +class _ZipReadableSeekableTellable(_ZipReadable, _ZipTellable, Protocol): ... class _ZipWritable(Protocol): def flush(self) -> None: ... @@ -164,7 +162,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadable | _ZipSeekTellable, + file: StrPath | _ZipReadableSeekableTellable, mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, @@ -210,7 +208,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadable | _ZipSeekTellable, + file: StrPath | _ZipReadableSeekableTellable, mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, From 814ab6bab9844b99ee5b875017167da5c6f29974 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:17:14 -0500 Subject: [PATCH 13/16] Shorten name --- stdlib/zipfile/__init__.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index aadcec81dd1b..bc0151ae4d2b 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -101,7 +101,7 @@ class _ZipReadable(Protocol): class _ZipTellable(Protocol): def tell(self) -> int: ... -class _ZipReadableSeekableTellable(_ZipReadable, _ZipTellable, Protocol): ... +class _ZipReadableTellable(_ZipReadable, _ZipTellable, Protocol): ... class _ZipWritable(Protocol): def flush(self) -> None: ... @@ -162,7 +162,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadableSeekableTellable, + file: StrPath | _ZipReadableTellable, mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, @@ -208,7 +208,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipReadableSeekableTellable, + file: StrPath | _ZipReadableTellable, mode: Literal["a"] = ..., compression: int = 0, allowZip64: bool = True, From 524d7d7a4541b59fbfb91dd424612be0b82dd8a4 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Fri, 5 Jul 2024 16:21:44 -0500 Subject: [PATCH 14/16] Fix tests --- stdlib/@tests/test_cases/check_zipfile.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index 0d9bc1826e21..98461bdbc26b 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -49,6 +49,11 @@ def flush(self) -> None: pass +class ReadTellableObj(ReadableObj): + def tell(self) -> int: + return 0 + + class SeekTellObj: def seek(self, offset: int, whence: int = 0) -> int: return 0 @@ -87,8 +92,12 @@ def write_zip(mode: Literal["r", "w", "x", "a"]) -> None: with zipfile.ZipFile(ReadableObj(), "r") as z: z.writestr("test.txt", "test") - # Readable object should work for "a" mode. - with zipfile.ZipFile(ReadableObj(), "a") as z: + # Readable/tellable object should work for "a" mode. + with zipfile.ZipFile(ReadTellableObj(), "a") as z: + z.writestr("test.txt", "test") + + # If it doesn't have 'tell' method, it should raise an error. + with zipfile.ZipFile(ReadableObj(), "a") as z: # type: ignore z.writestr("test.txt", "test") # Readable object should not work for "w" mode. @@ -118,7 +127,3 @@ def write_zip(mode: Literal["r", "w", "x", "a"]) -> None: # Seekable and Tellable object should work for "w" mode. with zipfile.ZipFile(SeekTellObj(), "w") as z: z.writestr("test.txt", "test") - - # Seekable and Tellable object should work for "a" mode. - with zipfile.ZipFile(SeekTellObj(), "a") as z: - z.writestr("test.txt", "test") From d98196ab5128bc54e5442dff57f1620eb8a67272 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 11 Aug 2024 13:04:17 -0500 Subject: [PATCH 15/16] Address feedback --- stdlib/@tests/test_cases/check_zipfile.py | 5 +++-- stdlib/zipfile/__init__.pyi | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index 98461bdbc26b..17ea971d791a 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -108,8 +108,9 @@ def write_zip(mode: Literal["r", "w", "x", "a"]) -> None: with zipfile.ZipFile(TellableObj(), mode) as z: # type: ignore z.writestr("test.txt", "test") - # Tellable object should work for "w" mode. - with zipfile.ZipFile(TellableObj(), "w") as z: + # Tellable object shouldn't work for "w" mode. + # As `__del__` will call close. + with zipfile.ZipFile(TellableObj(), "w") as z: # type: ignore z.writestr("test.txt", "test") # Writeable object should not work for any mode. diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index 9e3e533401a7..85eb2b6dfe1f 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -150,7 +150,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipTellable | _ZipWritable, + file: StrPath | _ZipWritable, mode: Literal["w", "x"] = ..., compression: int = 0, allowZip64: bool = True, @@ -197,7 +197,7 @@ class ZipFile: @overload def __init__( self, - file: StrPath | _ZipTellable | _ZipWritable, + file: StrPath | _ZipWritable, mode: Literal["w", "x"] = ..., compression: int = 0, allowZip64: bool = True, From cc520e2ff91cae3e7fcdd514c23632d48ce3b3f0 Mon Sep 17 00:00:00 2001 From: Maxwell Muoto <41130755+max-muoto@users.noreply.github.com> Date: Sun, 11 Aug 2024 13:06:57 -0500 Subject: [PATCH 16/16] Fix --- stdlib/@tests/test_cases/check_zipfile.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stdlib/@tests/test_cases/check_zipfile.py b/stdlib/@tests/test_cases/check_zipfile.py index 17ea971d791a..3012271ccd8b 100644 --- a/stdlib/@tests/test_cases/check_zipfile.py +++ b/stdlib/@tests/test_cases/check_zipfile.py @@ -125,6 +125,7 @@ def write_zip(mode: Literal["r", "w", "x", "a"]) -> None: with zipfile.ZipFile(SeekTellObj(), mode) as z: # type: ignore z.writestr("test.txt", "test") - # Seekable and Tellable object should work for "w" mode. - with zipfile.ZipFile(SeekTellObj(), "w") as z: + # Seekable and Tellable object shouldn't work for "w" mode. + # Cause `__del__` will call close. + with zipfile.ZipFile(SeekTellObj(), "w") as z: # type: ignore z.writestr("test.txt", "test")