From 78fc518ab89c43a6aa8d12dedc2d747c989158a0 Mon Sep 17 00:00:00 2001 From: Rogdham <3994389+Rogdham@users.noreply.github.com> Date: Sun, 11 May 2025 15:23:20 +0200 Subject: [PATCH] 3.14: PEP-784 compression except zstd (#13992) --- pyproject.toml | 2 ++ stdlib/@tests/stubtest_allowlists/py314.txt | 11 ++++---- .../stubtest_allowlists/win32-py314.txt | 1 + stdlib/VERSIONS | 3 ++- stdlib/_compression.pyi | 8 +++--- stdlib/bz2.pyi | 10 +++++--- stdlib/compression/__init__.pyi | 0 stdlib/compression/_common/__init__.pyi | 0 stdlib/compression/_common/_streams.pyi | 25 +++++++++++++++++++ stdlib/compression/bz2/__init__.pyi | 1 + stdlib/compression/gzip/__init__.pyi | 1 + stdlib/compression/lzma/__init__.pyi | 1 + stdlib/compression/zlib/__init__.pyi | 1 + stdlib/gzip.pyi | 10 +++++--- stdlib/lzma.pyi | 7 +++++- 15 files changed, 64 insertions(+), 17 deletions(-) create mode 100644 stdlib/compression/__init__.pyi create mode 100644 stdlib/compression/_common/__init__.pyi create mode 100644 stdlib/compression/_common/_streams.pyi create mode 100644 stdlib/compression/bz2/__init__.pyi create mode 100644 stdlib/compression/gzip/__init__.pyi create mode 100644 stdlib/compression/lzma/__init__.pyi create mode 100644 stdlib/compression/zlib/__init__.pyi diff --git a/pyproject.toml b/pyproject.toml index e1c07d518..b4a430f75 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -245,6 +245,8 @@ extra-standard-library = [ # Extra modules not recognized by Ruff # Added in Python 3.9 "zoneinfo", + # Added in Python 3.14 + "compression", ] known-first-party = ["_utils", "ts_utils"] diff --git a/stdlib/@tests/stubtest_allowlists/py314.txt b/stdlib/@tests/stubtest_allowlists/py314.txt index 3c5002e21..f56e9d6db 100644 --- a/stdlib/@tests/stubtest_allowlists/py314.txt +++ b/stdlib/@tests/stubtest_allowlists/py314.txt @@ -5,7 +5,6 @@ _asyncio.all_tasks _asyncio.future_add_to_awaited_by _asyncio.future_discard_from_awaited_by -_compression _ctypes.POINTER _ctypes.byref _ctypes.pointer @@ -69,11 +68,11 @@ builtins.staticmethod.__annotate__ builtins.staticmethod.__class_getitem__ code.compile_command codeop.compile_command -compression -compression.bz2 -compression.gzip -compression.lzma -compression.zlib +compression.gzip.GzipFile.readinto +compression.gzip.GzipFile.readinto +compression.gzip.GzipFile.readinto1 +compression.gzip.GzipFile.readinto1 +compression.gzip.compress compression.zstd concurrent.futures.__all__ concurrent.futures.InterpreterPoolExecutor diff --git a/stdlib/@tests/stubtest_allowlists/win32-py314.txt b/stdlib/@tests/stubtest_allowlists/win32-py314.txt index 9e2f612db..cf30f5056 100644 --- a/stdlib/@tests/stubtest_allowlists/win32-py314.txt +++ b/stdlib/@tests/stubtest_allowlists/win32-py314.txt @@ -23,6 +23,7 @@ asyncio.windows_events.WindowsSelectorEventLoopPolicy asyncio.windows_events._DefaultEventLoopPolicy asyncio.windows_events._WindowsProactorEventLoopPolicy asyncio.windows_events._WindowsSelectorEventLoopPolicy +compression.zlib.ZLIBNG_VERSION ctypes.c_double_complex ctypes.c_float_complex ctypes.c_longdouble_complex diff --git a/stdlib/VERSIONS b/stdlib/VERSIONS index 717cf7b4d..bea644c67 100644 --- a/stdlib/VERSIONS +++ b/stdlib/VERSIONS @@ -28,7 +28,7 @@ _bz2: 3.3- _codecs: 3.0- _collections_abc: 3.3- _compat_pickle: 3.1- -_compression: 3.5- +_compression: 3.5-3.13 _contextvars: 3.7- _csv: 3.0- _ctypes: 3.0- @@ -118,6 +118,7 @@ collections: 3.0- collections.abc: 3.3- colorsys: 3.0- compileall: 3.0- +compression: 3.14- concurrent: 3.2- configparser: 3.0- contextlib: 3.0- diff --git a/stdlib/_compression.pyi b/stdlib/_compression.pyi index a41a8142c..80d38b4db 100644 --- a/stdlib/_compression.pyi +++ b/stdlib/_compression.pyi @@ -1,4 +1,6 @@ -from _typeshed import WriteableBuffer +# _compression is replaced by compression._common._streams on Python 3.14+ (PEP-784) + +from _typeshed import Incomplete, WriteableBuffer from collections.abc import Callable from io import DEFAULT_BUFFER_SIZE, BufferedIOBase, RawIOBase from typing import Any, Protocol @@ -16,9 +18,9 @@ class DecompressReader(RawIOBase): def __init__( self, fp: _Reader, - decomp_factory: Callable[..., object], + decomp_factory: Callable[..., Incomplete], trailing_error: type[Exception] | tuple[type[Exception], ...] = (), - **decomp_args: Any, + **decomp_args: Any, # These are passed to decomp_factory. ) -> None: ... def readinto(self, b: WriteableBuffer) -> int: ... def read(self, size: int = -1) -> bytes: ... diff --git a/stdlib/bz2.pyi b/stdlib/bz2.pyi index 3b21fbcf7..0f9d00fbc 100644 --- a/stdlib/bz2.pyi +++ b/stdlib/bz2.pyi @@ -1,17 +1,21 @@ -import _compression +import sys from _bz2 import BZ2Compressor as BZ2Compressor, BZ2Decompressor as BZ2Decompressor -from _compression import BaseStream from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Iterable from typing import IO, Literal, Protocol, SupportsIndex, TextIO, overload from typing_extensions import Self, TypeAlias +if sys.version_info >= (3, 14): + from compression._common._streams import BaseStream, _Reader +else: + from _compression import BaseStream, _Reader + __all__ = ["BZ2File", "BZ2Compressor", "BZ2Decompressor", "open", "compress", "decompress"] # The following attributes and methods are optional: # def fileno(self) -> int: ... # def close(self) -> object: ... -class _ReadableFileobj(_compression._Reader, Protocol): ... +class _ReadableFileobj(_Reader, Protocol): ... class _WritableFileobj(Protocol): def write(self, b: bytes, /) -> object: ... diff --git a/stdlib/compression/__init__.pyi b/stdlib/compression/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stdlib/compression/_common/__init__.pyi b/stdlib/compression/_common/__init__.pyi new file mode 100644 index 000000000..e69de29bb diff --git a/stdlib/compression/_common/_streams.pyi b/stdlib/compression/_common/_streams.pyi new file mode 100644 index 000000000..6303a9b1d --- /dev/null +++ b/stdlib/compression/_common/_streams.pyi @@ -0,0 +1,25 @@ +from _typeshed import Incomplete, WriteableBuffer +from collections.abc import Callable +from io import DEFAULT_BUFFER_SIZE, BufferedIOBase, RawIOBase +from typing import Any, Protocol + +BUFFER_SIZE = DEFAULT_BUFFER_SIZE + +class _Reader(Protocol): + def read(self, n: int, /) -> bytes: ... + def seekable(self) -> bool: ... + def seek(self, n: int, /) -> Any: ... + +class BaseStream(BufferedIOBase): ... + +class DecompressReader(RawIOBase): + def __init__( + self, + fp: _Reader, + decomp_factory: Callable[..., Incomplete], # Consider backporting changes to _compression + trailing_error: type[Exception] | tuple[type[Exception], ...] = (), + **decomp_args: Any, # These are passed to decomp_factory. + ) -> None: ... + def readinto(self, b: WriteableBuffer) -> int: ... + def read(self, size: int = -1) -> bytes: ... + def seek(self, offset: int, whence: int = 0) -> int: ... diff --git a/stdlib/compression/bz2/__init__.pyi b/stdlib/compression/bz2/__init__.pyi new file mode 100644 index 000000000..9ddc39f27 --- /dev/null +++ b/stdlib/compression/bz2/__init__.pyi @@ -0,0 +1 @@ +from bz2 import * diff --git a/stdlib/compression/gzip/__init__.pyi b/stdlib/compression/gzip/__init__.pyi new file mode 100644 index 000000000..9422a735c --- /dev/null +++ b/stdlib/compression/gzip/__init__.pyi @@ -0,0 +1 @@ +from gzip import * diff --git a/stdlib/compression/lzma/__init__.pyi b/stdlib/compression/lzma/__init__.pyi new file mode 100644 index 000000000..936c3813d --- /dev/null +++ b/stdlib/compression/lzma/__init__.pyi @@ -0,0 +1 @@ +from lzma import * diff --git a/stdlib/compression/zlib/__init__.pyi b/stdlib/compression/zlib/__init__.pyi new file mode 100644 index 000000000..78d176c03 --- /dev/null +++ b/stdlib/compression/zlib/__init__.pyi @@ -0,0 +1 @@ +from zlib import * diff --git a/stdlib/gzip.pyi b/stdlib/gzip.pyi index b7fb40fbd..883456b1d 100644 --- a/stdlib/gzip.pyi +++ b/stdlib/gzip.pyi @@ -1,4 +1,3 @@ -import _compression import sys import zlib from _typeshed import ReadableBuffer, SizedBuffer, StrOrBytesPath @@ -6,6 +5,11 @@ from io import FileIO, TextIOWrapper from typing import Final, Literal, Protocol, overload from typing_extensions import TypeAlias +if sys.version_info >= (3, 14): + from compression._common._streams import BaseStream, DecompressReader +else: + from _compression import BaseStream, DecompressReader + __all__ = ["BadGzipFile", "GzipFile", "open", "compress", "decompress"] _ReadBinaryMode: TypeAlias = Literal["r", "rb"] @@ -84,7 +88,7 @@ class _PaddedFile: class BadGzipFile(OSError): ... -class GzipFile(_compression.BaseStream): +class GzipFile(BaseStream): myfileobj: FileIO | None mode: object name: str @@ -153,7 +157,7 @@ class GzipFile(_compression.BaseStream): def seek(self, offset: int, whence: int = 0) -> int: ... def readline(self, size: int | None = -1) -> bytes: ... -class _GzipReader(_compression.DecompressReader): +class _GzipReader(DecompressReader): def __init__(self, fp: _ReadableFileobj) -> None: ... def compress(data: SizedBuffer, compresslevel: int = 9, *, mtime: float | None = None) -> bytes: ... diff --git a/stdlib/lzma.pyi b/stdlib/lzma.pyi index 2f0279f59..b066d2224 100644 --- a/stdlib/lzma.pyi +++ b/stdlib/lzma.pyi @@ -1,4 +1,4 @@ -from _compression import BaseStream +import sys from _lzma import ( CHECK_CRC32 as CHECK_CRC32, CHECK_CRC64 as CHECK_CRC64, @@ -38,6 +38,11 @@ from _typeshed import ReadableBuffer, StrOrBytesPath from typing import IO, Literal, TextIO, overload from typing_extensions import Self, TypeAlias +if sys.version_info >= (3, 14): + from compression._common._streams import BaseStream +else: + from _compression import BaseStream + __all__ = [ "CHECK_NONE", "CHECK_CRC32",