From 149b210648c53b527d5c00370afdccd98d856e19 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 20 Aug 2025 11:14:36 -0700 Subject: [PATCH 01/21] Add @disjoint_base decorator in the stdlib --- .github/workflows/stubtest_stdlib.yml | 2 ++ stdlib/_asyncio.pyi | 4 ++- stdlib/_csv.pyi | 5 +++- stdlib/_hashlib.pyi | 3 ++- stdlib/_interpreters.pyi | 3 ++- stdlib/_io.pyi | 12 ++++++++- stdlib/_lsprof.pyi | 2 ++ stdlib/_multibytecodec.pyi | 5 ++++ stdlib/_pickle.pyi | 4 ++- stdlib/_queue.pyi | 2 ++ stdlib/_random.pyi | 3 ++- stdlib/_socket.pyi | 3 ++- stdlib/_ssl.pyi | 4 +-- stdlib/_struct.pyi | 3 ++- stdlib/_thread.pyi | 3 ++- stdlib/_threading_local.pyi | 4 ++- stdlib/array.pyi | 3 ++- stdlib/ast.pyi | 3 ++- stdlib/asyncio/events.pyi | 4 ++- stdlib/asyncio/transports.pyi | 3 +++ stdlib/asyncio/trsock.pyi | 3 ++- stdlib/builtins.pyi | 37 +++++++++++++++++++++++++-- stdlib/collections/__init__.pyi | 5 +++- stdlib/dataclasses.pyi | 4 ++- stdlib/datetime.pyi | 6 ++++- stdlib/decimal.pyi | 4 ++- stdlib/fractions.pyi | 3 ++- stdlib/functools.pyi | 4 +-- stdlib/hmac.pyi | 4 +-- stdlib/inspect.pyi | 5 +++- stdlib/ipaddress.pyi | 4 ++- stdlib/itertools.pyi | 22 ++++++++++++++-- stdlib/mmap.pyi | 3 ++- stdlib/multiprocessing/managers.pyi | 3 ++- stdlib/pathlib/__init__.pyi | 3 ++- stdlib/pickletools.pyi | 5 +++- stdlib/socket.pyi | 3 ++- stdlib/sqlite3/__init__.pyi | 5 +++- stdlib/statistics.pyi | 4 +-- stdlib/tarfile.pyi | 4 +-- stdlib/traceback.pyi | 3 ++- stdlib/tracemalloc.pyi | 7 ++++- stdlib/types.pyi | 6 +++-- stdlib/uuid.pyi | 3 ++- stdlib/weakref.pyi | 5 +++- stdlib/xml/dom/expatbuilder.pyi | 5 +++- stdlib/xml/dom/minidom.pyi | 12 ++++++++- stdlib/xml/dom/xmlbuilder.pyi | 3 +++ stdlib/xml/etree/ElementTree.pyi | 5 +++- stdlib/zipfile/__init__.pyi | 3 ++- stdlib/zoneinfo/__init__.pyi | 3 ++- 51 files changed, 208 insertions(+), 53 deletions(-) diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index 2a574584ff08..f6d8a91883c4 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -46,5 +46,7 @@ jobs: check-latest: true - name: Install dependencies run: pip install -r requirements-tests.txt + - name: Install mypy from git + run: pip install git+https://github.com/python/mypy.git@657bdd84cff780a4b96c04525e2693c074a3fbf3 - name: Run stubtest run: python tests/stubtest_stdlib.py diff --git a/stdlib/_asyncio.pyi b/stdlib/_asyncio.pyi index ed56f33af93a..4a66c7d0e3e7 100644 --- a/stdlib/_asyncio.pyi +++ b/stdlib/_asyncio.pyi @@ -4,12 +4,13 @@ from collections.abc import Awaitable, Callable, Coroutine, Generator from contextvars import Context from types import FrameType, GenericAlias from typing import Any, Literal, TextIO, TypeVar -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) _TaskYieldType: TypeAlias = Future[object] | None +@disjoint_base class Future(Awaitable[_T]): _state: str @property @@ -49,6 +50,7 @@ else: # While this is true in general, here it's sort-of okay to have a covariant subclass, # since the only reason why `asyncio.Future` is invariant is the `set_result()` method, # and `asyncio.Task.set_result()` always raises. +@disjoint_base class Task(Future[_T_co]): # type: ignore[type-var] # pyright: ignore[reportInvalidTypeArguments] if sys.version_info >= (3, 12): def __init__( diff --git a/stdlib/_csv.pyi b/stdlib/_csv.pyi index efe9ad69bd31..bc15d516f423 100644 --- a/stdlib/_csv.pyi +++ b/stdlib/_csv.pyi @@ -3,7 +3,7 @@ import sys from _typeshed import SupportsWrite from collections.abc import Iterable from typing import Any, Final, Literal, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base __version__: Final[str] @@ -24,6 +24,7 @@ class Error(Exception): ... _DialectLike: TypeAlias = str | Dialect | csv.Dialect | type[Dialect | csv.Dialect] +@disjoint_base class Dialect: delimiter: str quotechar: str | None @@ -48,6 +49,7 @@ class Dialect: if sys.version_info >= (3, 10): # This class calls itself _csv.reader. + @disjoint_base class Reader: @property def dialect(self) -> Dialect: ... @@ -56,6 +58,7 @@ if sys.version_info >= (3, 10): def __next__(self) -> list[str]: ... # This class calls itself _csv.writer. + @disjoint_base class Writer: @property def dialect(self) -> Dialect: ... diff --git a/stdlib/_hashlib.pyi b/stdlib/_hashlib.pyi index 8b7ef52cdffd..03c1eef3be3f 100644 --- a/stdlib/_hashlib.pyi +++ b/stdlib/_hashlib.pyi @@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer from collections.abc import Callable from types import ModuleType from typing import AnyStr, Protocol, final, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base _DigestMod: TypeAlias = str | Callable[[], _HashObject] | ModuleType | None @@ -22,6 +22,7 @@ class _HashObject(Protocol): def hexdigest(self) -> str: ... def update(self, obj: ReadableBuffer, /) -> None: ... +@disjoint_base class HASH: @property def digest_size(self) -> int: ... diff --git a/stdlib/_interpreters.pyi b/stdlib/_interpreters.pyi index f89a24e7d85c..cb83e009794a 100644 --- a/stdlib/_interpreters.pyi +++ b/stdlib/_interpreters.pyi @@ -1,7 +1,7 @@ import types from collections.abc import Callable from typing import Any, Final, Literal, SupportsIndex, TypeVar -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base _R = TypeVar("_R") @@ -12,6 +12,7 @@ class InterpreterError(Exception): ... class InterpreterNotFoundError(InterpreterError): ... class NotShareableError(ValueError): ... +@disjoint_base class CrossInterpreterBufferView: def __buffer__(self, flags: int, /) -> memoryview: ... diff --git a/stdlib/_io.pyi b/stdlib/_io.pyi index e368ddef7f4e..d1c2de99f3cb 100644 --- a/stdlib/_io.pyi +++ b/stdlib/_io.pyi @@ -7,7 +7,7 @@ from io import BufferedIOBase, RawIOBase, TextIOBase, UnsupportedOperation as Un from os import _Opener from types import TracebackType from typing import IO, Any, BinaryIO, Final, Generic, Literal, Protocol, TextIO, TypeVar, overload, type_check_only -from typing_extensions import Self +from typing_extensions import Self, disjoint_base _T = TypeVar("_T") @@ -19,6 +19,7 @@ def open_code(path: str) -> IO[bytes]: ... BlockingIOError = builtins.BlockingIOError +@disjoint_base class _IOBase: def __iter__(self) -> Iterator[bytes]: ... def __next__(self) -> bytes: ... @@ -62,6 +63,7 @@ class _BufferedIOBase(_IOBase): def read(self, size: int | None = -1, /) -> bytes: ... def read1(self, size: int = -1, /) -> bytes: ... +@disjoint_base class FileIO(RawIOBase, _RawIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes mode: str # The type of "name" equals the argument passed in to the constructor, @@ -76,6 +78,7 @@ class FileIO(RawIOBase, _RawIOBase, BinaryIO): # type: ignore[misc] # incompat def seek(self, pos: int, whence: int = 0, /) -> int: ... def read(self, size: int | None = -1, /) -> bytes | MaybeNone: ... +@disjoint_base class BytesIO(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes def __init__(self, initial_bytes: ReadableBuffer = b"") -> None: ... # BytesIO does not contain a "name" field. This workaround is necessary @@ -116,6 +119,7 @@ class _BufferedReaderStream(Protocol): _BufferedReaderStreamT = TypeVar("_BufferedReaderStreamT", bound=_BufferedReaderStream, default=_BufferedReaderStream) +@disjoint_base class BufferedReader(BufferedIOBase, _BufferedIOBase, BinaryIO, Generic[_BufferedReaderStreamT]): # type: ignore[misc] # incompatible definitions of methods in the base classes raw: _BufferedReaderStreamT def __init__(self, raw: _BufferedReaderStreamT, buffer_size: int = 8192) -> None: ... @@ -123,6 +127,7 @@ class BufferedReader(BufferedIOBase, _BufferedIOBase, BinaryIO, Generic[_Buffere def seek(self, target: int, whence: int = 0, /) -> int: ... def truncate(self, pos: int | None = None, /) -> int: ... +@disjoint_base class BufferedWriter(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of writelines in the base classes raw: RawIOBase def __init__(self, raw: RawIOBase, buffer_size: int = 8192) -> None: ... @@ -130,6 +135,7 @@ class BufferedWriter(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore def seek(self, target: int, whence: int = 0, /) -> int: ... def truncate(self, pos: int | None = None, /) -> int: ... +@disjoint_base class BufferedRandom(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore[misc] # incompatible definitions of methods in the base classes mode: str name: Any @@ -139,6 +145,7 @@ class BufferedRandom(BufferedIOBase, _BufferedIOBase, BinaryIO): # type: ignore def peek(self, size: int = 0, /) -> bytes: ... def truncate(self, pos: int | None = None, /) -> int: ... +@disjoint_base class BufferedRWPair(BufferedIOBase, _BufferedIOBase, Generic[_BufferedReaderStreamT]): def __init__(self, reader: _BufferedReaderStreamT, writer: RawIOBase, buffer_size: int = 8192, /) -> None: ... def peek(self, size: int = 0, /) -> bytes: ... @@ -181,6 +188,7 @@ class _WrappedBuffer(Protocol): _BufferT_co = TypeVar("_BufferT_co", bound=_WrappedBuffer, default=_WrappedBuffer, covariant=True) +@disjoint_base class TextIOWrapper(TextIOBase, _TextIOBase, TextIO, Generic[_BufferT_co]): # type: ignore[misc] # incompatible definitions of write in the base classes def __init__( self, @@ -215,6 +223,7 @@ class TextIOWrapper(TextIOBase, _TextIOBase, TextIO, Generic[_BufferT_co]): # t def seek(self, cookie: int, whence: int = 0, /) -> int: ... def truncate(self, pos: int | None = None, /) -> int: ... +@disjoint_base class StringIO(TextIOBase, _TextIOBase, TextIO): # type: ignore[misc] # incompatible definitions of write in the base classes def __init__(self, initial_value: str | None = "", newline: str | None = "\n") -> None: ... # StringIO does not contain a "name" field. This workaround is necessary @@ -227,6 +236,7 @@ class StringIO(TextIOBase, _TextIOBase, TextIO): # type: ignore[misc] # incomp def seek(self, pos: int, whence: int = 0, /) -> int: ... def truncate(self, pos: int | None = None, /) -> int: ... +@disjoint_base class IncrementalNewlineDecoder: def __init__(self, decoder: codecs.IncrementalDecoder | None, translate: bool, errors: str = "strict") -> None: ... def decode(self, input: ReadableBuffer | str, final: bool = False) -> str: ... diff --git a/stdlib/_lsprof.pyi b/stdlib/_lsprof.pyi index 8a6934162c92..4f6d98b8ffb6 100644 --- a/stdlib/_lsprof.pyi +++ b/stdlib/_lsprof.pyi @@ -3,7 +3,9 @@ from _typeshed import structseq from collections.abc import Callable from types import CodeType from typing import Any, Final, final +from typing_extensions import disjoint_base +@disjoint_base class Profiler: def __init__( self, timer: Callable[[], float] | None = None, timeunit: float = 0.0, subcalls: bool = True, builtins: bool = True diff --git a/stdlib/_multibytecodec.pyi b/stdlib/_multibytecodec.pyi index 7e408f2aa30e..abe58cb64f31 100644 --- a/stdlib/_multibytecodec.pyi +++ b/stdlib/_multibytecodec.pyi @@ -2,6 +2,7 @@ from _typeshed import ReadableBuffer from codecs import _ReadableStream, _WritableStream from collections.abc import Iterable from typing import final, type_check_only +from typing_extensions import disjoint_base # This class is not exposed. It calls itself _multibytecodec.MultibyteCodec. @final @@ -10,6 +11,7 @@ class _MultibyteCodec: def decode(self, input: ReadableBuffer, errors: str | None = None) -> str: ... def encode(self, input: str, errors: str | None = None) -> bytes: ... +@disjoint_base class MultibyteIncrementalDecoder: errors: str def __init__(self, errors: str = "strict") -> None: ... @@ -18,6 +20,7 @@ class MultibyteIncrementalDecoder: def reset(self) -> None: ... def setstate(self, state: tuple[bytes, int], /) -> None: ... +@disjoint_base class MultibyteIncrementalEncoder: errors: str def __init__(self, errors: str = "strict") -> None: ... @@ -26,6 +29,7 @@ class MultibyteIncrementalEncoder: def reset(self) -> None: ... def setstate(self, state: int, /) -> None: ... +@disjoint_base class MultibyteStreamReader: errors: str stream: _ReadableStream @@ -35,6 +39,7 @@ class MultibyteStreamReader: def readlines(self, sizehintobj: int | None = None, /) -> list[str]: ... def reset(self) -> None: ... +@disjoint_base class MultibyteStreamWriter: errors: str stream: _WritableStream diff --git a/stdlib/_pickle.pyi b/stdlib/_pickle.pyi index 03051bb09d3c..544f787172d6 100644 --- a/stdlib/_pickle.pyi +++ b/stdlib/_pickle.pyi @@ -2,7 +2,7 @@ from _typeshed import ReadableBuffer, SupportsWrite from collections.abc import Callable, Iterable, Iterator, Mapping from pickle import PickleBuffer as PickleBuffer from typing import Any, Protocol, type_check_only -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base @type_check_only class _ReadableFileobj(Protocol): @@ -57,6 +57,7 @@ class PicklerMemoProxy: def clear(self, /) -> None: ... def copy(self, /) -> dict[int, tuple[int, Any]]: ... +@disjoint_base class Pickler: fast: bool dispatch_table: Mapping[type, Callable[[Any], _ReducedType]] @@ -84,6 +85,7 @@ class UnpicklerMemoProxy: def clear(self, /) -> None: ... def copy(self, /) -> dict[int, tuple[int, Any]]: ... +@disjoint_base class Unpickler: def __init__( self, diff --git a/stdlib/_queue.pyi b/stdlib/_queue.pyi index f98397b132ab..edd484a9a71a 100644 --- a/stdlib/_queue.pyi +++ b/stdlib/_queue.pyi @@ -1,10 +1,12 @@ from types import GenericAlias from typing import Any, Generic, TypeVar +from typing_extensions import disjoint_base _T = TypeVar("_T") class Empty(Exception): ... +@disjoint_base class SimpleQueue(Generic[_T]): def __init__(self) -> None: ... def empty(self) -> bool: ... diff --git a/stdlib/_random.pyi b/stdlib/_random.pyi index 4082344ade8e..7df9ec42d7f2 100644 --- a/stdlib/_random.pyi +++ b/stdlib/_random.pyi @@ -1,8 +1,9 @@ -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base # Actually Tuple[(int,) * 625] _State: TypeAlias = tuple[int, ...] +@disjoint_base class Random: def __init__(self, seed: object = ...) -> None: ... def seed(self, n: object = None, /) -> None: ... diff --git a/stdlib/_socket.pyi b/stdlib/_socket.pyi index 9c153a3a6ba0..cdad886b3415 100644 --- a/stdlib/_socket.pyi +++ b/stdlib/_socket.pyi @@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer, WriteableBuffer from collections.abc import Iterable from socket import error as error, gaierror as gaierror, herror as herror, timeout as timeout from typing import Any, Final, SupportsIndex, overload -from typing_extensions import CapsuleType, TypeAlias +from typing_extensions import CapsuleType, TypeAlias, disjoint_base _CMSG: TypeAlias = tuple[int, int, bytes] _CMSGArg: TypeAlias = tuple[int, int, ReadableBuffer] @@ -731,6 +731,7 @@ if sys.platform != "win32" and sys.platform != "darwin": # ===== Classes ===== +@disjoint_base class socket: @property def family(self) -> int: ... diff --git a/stdlib/_ssl.pyi b/stdlib/_ssl.pyi index 8afa3e5297bd..73a43f29c8c5 100644 --- a/stdlib/_ssl.pyi +++ b/stdlib/_ssl.pyi @@ -13,7 +13,7 @@ from ssl import ( SSLZeroReturnError as SSLZeroReturnError, ) from typing import Any, ClassVar, Final, Literal, TypedDict, final, overload, type_check_only -from typing_extensions import NotRequired, Self, TypeAlias, deprecated +from typing_extensions import NotRequired, Self, TypeAlias, deprecated, disjoint_base _PasswordType: TypeAlias = Callable[[], str | bytes | bytearray] | str | bytes | bytearray _PCTRTT: TypeAlias = tuple[tuple[str, str], ...] @@ -67,7 +67,7 @@ if sys.platform == "win32": def txt2obj(txt: str, name: bool = False) -> tuple[int, str, str, str]: ... def nid2obj(nid: int, /) -> tuple[int, str, str, str]: ... - +@disjoint_base class _SSLContext: check_hostname: bool keylog_filename: str | None diff --git a/stdlib/_struct.pyi b/stdlib/_struct.pyi index 662170e869f3..a8fac2aea1b0 100644 --- a/stdlib/_struct.pyi +++ b/stdlib/_struct.pyi @@ -1,6 +1,7 @@ from _typeshed import ReadableBuffer, WriteableBuffer from collections.abc import Iterator from typing import Any +from typing_extensions import disjoint_base def pack(fmt: str | bytes, /, *v: Any) -> bytes: ... def pack_into(fmt: str | bytes, buffer: WriteableBuffer, offset: int, /, *v: Any) -> None: ... @@ -8,7 +9,7 @@ def unpack(format: str | bytes, buffer: ReadableBuffer, /) -> tuple[Any, ...]: . def unpack_from(format: str | bytes, /, buffer: ReadableBuffer, offset: int = 0) -> tuple[Any, ...]: ... def iter_unpack(format: str | bytes, buffer: ReadableBuffer, /) -> Iterator[tuple[Any, ...]]: ... def calcsize(format: str | bytes, /) -> int: ... - +@disjoint_base class Struct: @property def format(self) -> str: ... diff --git a/stdlib/_thread.pyi b/stdlib/_thread.pyi index fb9a3eeb9857..6969ae48cae7 100644 --- a/stdlib/_thread.pyi +++ b/stdlib/_thread.pyi @@ -5,7 +5,7 @@ from collections.abc import Callable from threading import Thread from types import TracebackType from typing import Any, Final, NoReturn, final, overload -from typing_extensions import TypeVarTuple, Unpack +from typing_extensions import TypeVarTuple, Unpack, disjoint_base _Ts = TypeVarTuple("_Ts") @@ -110,6 +110,7 @@ if sys.version_info >= (3, 12): if sys.version_info >= (3, 14): def set_name(name: str) -> None: ... +@disjoint_base class _local: def __getattribute__(self, name: str, /) -> Any: ... def __setattr__(self, name: str, value: Any, /) -> None: ... diff --git a/stdlib/_threading_local.pyi b/stdlib/_threading_local.pyi index 07a825f0d816..7e2e27258e40 100644 --- a/stdlib/_threading_local.pyi +++ b/stdlib/_threading_local.pyi @@ -1,11 +1,12 @@ from threading import RLock from typing import Any -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base from weakref import ReferenceType __all__ = ["local"] _LocalDict: TypeAlias = dict[Any, Any] +@disjoint_base class _localimpl: key: str dicts: dict[int, tuple[ReferenceType[Any], _LocalDict]] @@ -15,6 +16,7 @@ class _localimpl: def get_dict(self) -> _LocalDict: ... def create_dict(self) -> _LocalDict: ... +@disjoint_base class local: def __new__(cls, /, *args: Any, **kw: Any) -> Self: ... def __getattribute__(self, name: str) -> Any: ... diff --git a/stdlib/array.pyi b/stdlib/array.pyi index ccb7f1b98ef3..a6b0344a1e2e 100644 --- a/stdlib/array.pyi +++ b/stdlib/array.pyi @@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer, SupportsRead, SupportsWrite from collections.abc import Iterable, MutableSequence from types import GenericAlias from typing import Any, ClassVar, Literal, SupportsIndex, TypeVar, overload -from typing_extensions import Self, TypeAlias, deprecated +from typing_extensions import Self, TypeAlias, deprecated, disjoint_base _IntTypeCode: TypeAlias = Literal["b", "B", "h", "H", "i", "I", "l", "L", "q", "Q"] _FloatTypeCode: TypeAlias = Literal["f", "d"] @@ -17,6 +17,7 @@ _T = TypeVar("_T", int, float, str) typecodes: str +@disjoint_base class array(MutableSequence[_T]): @property def typecode(self) -> _TypeCode: ... diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index 8ee867116301..5f82156c2c40 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -11,7 +11,7 @@ from _ast import ( from _typeshed import ReadableBuffer, Unused from collections.abc import Iterable, Iterator, Sequence from typing import Any, ClassVar, Generic, Literal, TypedDict, TypeVar as _TypeVar, overload, type_check_only -from typing_extensions import Self, Unpack, deprecated +from typing_extensions import Self, Unpack, deprecated, disjoint_base if sys.version_info >= (3, 13): from _ast import PyCF_OPTIMIZED_AST as PyCF_OPTIMIZED_AST @@ -30,6 +30,7 @@ class _Attributes(TypedDict, Generic[_EndPositionT], total=False): # The various AST classes are implemented in C, and imported from _ast at runtime, # but they consider themselves to live in the ast module, # so we'll define the stubs in this file. +@disjoint_base class AST: if sys.version_info >= (3, 10): __match_args__ = () diff --git a/stdlib/asyncio/events.pyi b/stdlib/asyncio/events.pyi index a37f6f697b9a..81c72877f672 100644 --- a/stdlib/asyncio/events.pyi +++ b/stdlib/asyncio/events.pyi @@ -13,7 +13,7 @@ from concurrent.futures import Executor from contextvars import Context from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket from typing import IO, Any, Literal, Protocol, TypeVar, overload, type_check_only -from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack, deprecated +from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack, deprecated, disjoint_base from . import _AwaitableLike, _CoroutineLike from .base_events import Server @@ -72,6 +72,7 @@ _SSLContext: TypeAlias = bool | None | ssl.SSLContext class _TaskFactory(Protocol): def __call__(self, loop: AbstractEventLoop, factory: _CoroutineLike[_T], /) -> Future[_T]: ... +@disjoint_base class Handle: _cancelled: bool _args: Sequence[Any] @@ -84,6 +85,7 @@ class Handle: if sys.version_info >= (3, 12): def get_context(self) -> Context: ... +@disjoint_base class TimerHandle(Handle): def __init__( self, diff --git a/stdlib/asyncio/transports.pyi b/stdlib/asyncio/transports.pyi index bce54897f18f..32158530ddbc 100644 --- a/stdlib/asyncio/transports.pyi +++ b/stdlib/asyncio/transports.pyi @@ -3,10 +3,12 @@ from asyncio.protocols import BaseProtocol from collections.abc import Iterable, Mapping from socket import _Address from typing import Any +from typing_extensions import disjoint_base # Keep asyncio.__all__ updated with any changes to __all__ here __all__ = ("BaseTransport", "ReadTransport", "WriteTransport", "Transport", "DatagramTransport", "SubprocessTransport") +@disjoint_base class BaseTransport: def __init__(self, extra: Mapping[str, Any] | None = None) -> None: ... def get_extra_info(self, name: str, default: Any = None) -> Any: ... @@ -46,5 +48,6 @@ class SubprocessTransport(BaseTransport): def terminate(self) -> None: ... def kill(self) -> None: ... +@disjoint_base class _FlowControlMixin(Transport): def __init__(self, extra: Mapping[str, Any] | None = None, loop: AbstractEventLoop | None = None) -> None: ... diff --git a/stdlib/asyncio/trsock.pyi b/stdlib/asyncio/trsock.pyi index 4dacbbd49399..d41a26ddebf5 100644 --- a/stdlib/asyncio/trsock.pyi +++ b/stdlib/asyncio/trsock.pyi @@ -5,7 +5,7 @@ from builtins import type as Type # alias to avoid name clashes with property n from collections.abc import Iterable from types import TracebackType from typing import Any, BinaryIO, NoReturn, overload -from typing_extensions import TypeAlias, deprecated +from typing_extensions import TypeAlias, deprecated, disjoint_base # These are based in socket, maybe move them out into _typeshed.pyi or such _Address: TypeAlias = socket._Address @@ -13,6 +13,7 @@ _RetAddress: TypeAlias = Any _WriteBuffer: TypeAlias = bytearray | memoryview _CMSG: TypeAlias = tuple[int, int, bytes] +@disjoint_base class TransportSocket: def __init__(self, sock: socket.socket) -> None: ... @property diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index c7ab95482f6b..02e42096dee6 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -71,6 +71,7 @@ from typing_extensions import ( # noqa: Y023 TypeIs, TypeVarTuple, deprecated, + disjoint_base, ) if sys.version_info >= (3, 14): @@ -103,6 +104,7 @@ _StopT_co = TypeVar("_StopT_co", covariant=True, default=_StartT_co) # slice[A # FIXME: https://github.com/python/typing/issues/213 (replace step=start|stop with step=start&stop) _StepT_co = TypeVar("_StepT_co", covariant=True, default=_StartT_co | _StopT_co) # slice[A,B] -> slice[A, B, A|B] +@disjoint_base class object: __doc__: str | None __dict__: dict[str, Any] @@ -138,6 +140,7 @@ class object: @classmethod def __subclasshook__(cls, subclass: type, /) -> bool: ... +@disjoint_base class staticmethod(Generic[_P, _R_co]): @property def __func__(self) -> Callable[_P, _R_co]: ... @@ -158,6 +161,7 @@ class staticmethod(Generic[_P, _R_co]): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... __annotate__: AnnotateFunc | None +@disjoint_base class classmethod(Generic[_T, _P, _R_co]): @property def __func__(self) -> Callable[Concatenate[type[_T], _P], _R_co]: ... @@ -177,6 +181,7 @@ class classmethod(Generic[_T, _P, _R_co]): def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... __annotate__: AnnotateFunc | None +@disjoint_base class type: # object.__base__ is None. Otherwise, it would be a type. @property @@ -229,6 +234,7 @@ class type: if sys.version_info >= (3, 14): __annotate__: AnnotateFunc | None +@disjoint_base class super: @overload def __init__(self, t: Any, obj: Any, /) -> None: ... @@ -241,6 +247,7 @@ _PositiveInteger: TypeAlias = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, _NegativeInteger: TypeAlias = Literal[-1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20] _LiteralInteger = _PositiveInteger | _NegativeInteger | Literal[0] # noqa: Y026 # TODO: Use TypeAlias once mypy bugs are fixed +@disjoint_base class int: @overload def __new__(cls, x: ConvertibleToInt = ..., /) -> Self: ... @@ -351,6 +358,7 @@ class int: def __index__(self) -> int: ... def __format__(self, format_spec: str, /) -> str: ... +@disjoint_base class float: def __new__(cls, x: ConvertibleToFloat = ..., /) -> Self: ... def as_integer_ratio(self) -> tuple[int, int]: ... @@ -416,6 +424,7 @@ class float: @classmethod def from_number(cls, number: float | SupportsIndex | SupportsFloat, /) -> Self: ... +@disjoint_base class complex: # Python doesn't currently accept SupportsComplex for the second argument @overload @@ -463,6 +472,7 @@ class _FormatMapMapping(Protocol): class _TranslateTable(Protocol): def __getitem__(self, key: int, /) -> str | int | None: ... +@disjoint_base class str(Sequence[str]): @overload def __new__(cls, object: object = ...) -> Self: ... @@ -647,6 +657,7 @@ class str(Sequence[str]): def __getnewargs__(self) -> tuple[str]: ... def __format__(self, format_spec: str, /) -> str: ... +@disjoint_base class bytes(Sequence[int]): @overload def __new__(cls, o: Iterable[SupportsIndex] | SupportsIndex | SupportsBytes | ReadableBuffer, /) -> Self: ... @@ -745,6 +756,7 @@ class bytes(Sequence[int]): def __buffer__(self, flags: int, /) -> memoryview: ... +@disjoint_base class bytearray(MutableSequence[int]): @overload def __init__(self) -> None: ... @@ -1009,6 +1021,7 @@ class slice(Generic[_StartT_co, _StopT_co, _StepT_co]): def indices(self, len: SupportsIndex, /) -> tuple[int, int, int]: ... +@disjoint_base class tuple(Sequence[_T_co]): def __new__(cls, iterable: Iterable[_T_co] = ..., /) -> Self: ... def __len__(self) -> int: ... @@ -1085,6 +1098,7 @@ class function: # mypy uses `builtins.function.__get__` to represent methods, properties, and getset_descriptors so we type the return as Any. def __get__(self, instance: object, owner: type | None = None, /) -> Any: ... +@disjoint_base class list(MutableSequence[_T]): @overload def __init__(self) -> None: ... @@ -1139,6 +1153,7 @@ class list(MutableSequence[_T]): def __eq__(self, value: object, /) -> bool: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... +@disjoint_base class dict(MutableMapping[_KT, _VT]): # __init__ should be kept roughly in line with `collections.UserDict.__init__`, which has similar semantics # Also multiprocessing.managers.SyncManager.dict() @@ -1221,6 +1236,7 @@ class dict(MutableMapping[_KT, _VT]): @overload def __ior__(self, value: Iterable[tuple[_KT, _VT]], /) -> Self: ... +@disjoint_base class set(MutableSet[_T]): @overload def __init__(self) -> None: ... @@ -1260,6 +1276,7 @@ class set(MutableSet[_T]): __hash__: ClassVar[None] # type: ignore[assignment] def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... +@disjoint_base class frozenset(AbstractSet[_T_co]): @overload def __new__(cls) -> Self: ... @@ -1288,6 +1305,7 @@ class frozenset(AbstractSet[_T_co]): def __hash__(self) -> int: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... +@disjoint_base class enumerate(Generic[_T]): def __new__(cls, iterable: Iterable[_T], start: int = 0) -> Self: ... def __iter__(self) -> Self: ... @@ -1319,6 +1337,7 @@ class range(Sequence[int]): def __getitem__(self, key: slice, /) -> range: ... def __reversed__(self) -> Iterator[int]: ... +@disjoint_base class property: fget: Callable[[Any], Any] | None fset: Callable[[Any, Any], None] | None @@ -1482,6 +1501,7 @@ else: exit: _sitebuiltins.Quitter +@disjoint_base class filter(Generic[_T]): @overload def __new__(cls, function: None, iterable: Iterable[_T | None], /) -> Self: ... @@ -1545,7 +1565,7 @@ def len(obj: Sized, /) -> int: ... license: _sitebuiltins._Printer def locals() -> dict[str, Any]: ... - +@disjoint_base class map(Generic[_S]): # 3.14 adds `strict` argument. if sys.version_info >= (3, 14): @@ -1852,6 +1872,7 @@ def pow(base: _SupportsSomeKindOfPow, exp: complex, mod: None = None) -> complex quit: _sitebuiltins.Quitter +@disjoint_base class reversed(Generic[_T]): @overload def __new__(cls, sequence: Reversible[_T], /) -> Iterator[_T]: ... # type: ignore[misc] @@ -1915,7 +1936,7 @@ def sum(iterable: Iterable[_AddableT1], /, start: _AddableT2) -> _AddableT1 | _A def vars(object: type, /) -> types.MappingProxyType[str, Any]: ... @overload def vars(object: Any = ..., /) -> dict[str, Any]: ... - +@disjoint_base class zip(Generic[_T_co]): if sys.version_info >= (3, 10): @overload @@ -2019,6 +2040,7 @@ else: Ellipsis: ellipsis +@disjoint_base class BaseException: args: tuple[Any, ...] __cause__: BaseException | None @@ -2037,14 +2059,17 @@ class BaseException: class GeneratorExit(BaseException): ... class KeyboardInterrupt(BaseException): ... +@disjoint_base class SystemExit(BaseException): code: sys._ExitCode class Exception(BaseException): ... +@disjoint_base class StopIteration(Exception): value: Any +@disjoint_base class OSError(Exception): errno: int | None strerror: str | None @@ -2062,6 +2087,7 @@ if sys.platform == "win32": class ArithmeticError(Exception): ... class AssertionError(Exception): ... +@disjoint_base class AttributeError(Exception): if sys.version_info >= (3, 10): def __init__(self, *args: object, name: str | None = ..., obj: object = ...) -> None: ... @@ -2071,6 +2097,7 @@ class AttributeError(Exception): class BufferError(Exception): ... class EOFError(Exception): ... +@disjoint_base class ImportError(Exception): def __init__(self, *args: object, name: str | None = ..., path: str | None = ...) -> None: ... name: str | None @@ -2082,6 +2109,7 @@ class ImportError(Exception): class LookupError(Exception): ... class MemoryError(Exception): ... +@disjoint_base class NameError(Exception): if sys.version_info >= (3, 10): def __init__(self, *args: object, name: str | None = ...) -> None: ... @@ -2091,6 +2119,7 @@ class ReferenceError(Exception): ... class RuntimeError(Exception): ... class StopAsyncIteration(Exception): ... +@disjoint_base class SyntaxError(Exception): msg: str filename: str | None @@ -2154,6 +2183,7 @@ class IndentationError(SyntaxError): ... class TabError(IndentationError): ... class UnicodeError(ValueError): ... +@disjoint_base class UnicodeDecodeError(UnicodeError): encoding: str object: bytes @@ -2162,6 +2192,7 @@ class UnicodeDecodeError(UnicodeError): reason: str def __init__(self, encoding: str, object: ReadableBuffer, start: int, end: int, reason: str, /) -> None: ... +@disjoint_base class UnicodeEncodeError(UnicodeError): encoding: str object: str @@ -2170,6 +2201,7 @@ class UnicodeEncodeError(UnicodeError): reason: str def __init__(self, encoding: str, object: str, start: int, end: int, reason: str, /) -> None: ... +@disjoint_base class UnicodeTranslateError(UnicodeError): encoding: None object: str @@ -2200,6 +2232,7 @@ if sys.version_info >= (3, 11): _ExceptionT = TypeVar("_ExceptionT", bound=Exception) # See `check_exception_group.py` for use-cases and comments. + @disjoint_base class BaseExceptionGroup(BaseException, Generic[_BaseExceptionT_co]): def __new__(cls, message: str, exceptions: Sequence[_BaseExceptionT_co], /) -> Self: ... def __init__(self, message: str, exceptions: Sequence[_BaseExceptionT_co], /) -> None: ... diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index df9449ef4c9b..2df6c67d5bff 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -3,7 +3,7 @@ from _collections_abc import dict_items, dict_keys, dict_values from _typeshed import SupportsItems, SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT from types import GenericAlias from typing import Any, ClassVar, Generic, NoReturn, SupportsIndex, TypeVar, final, overload, type_check_only -from typing_extensions import Self +from typing_extensions import Self, disjoint_base if sys.version_info >= (3, 10): from collections.abc import ( @@ -231,6 +231,7 @@ class UserString(Sequence[UserString]): def upper(self) -> Self: ... def zfill(self, width: int) -> Self: ... +@disjoint_base class deque(MutableSequence[_T]): @property def maxlen(self) -> int | None: ... @@ -356,6 +357,7 @@ class _odict_items(dict_items[_KT_co, _VT_co]): # type: ignore[misc] # pyright class _odict_values(dict_values[_KT_co, _VT_co]): # type: ignore[misc] # pyright: ignore[reportGeneralTypeIssues] def __reversed__(self) -> Iterator[_VT_co]: ... +@disjoint_base class OrderedDict(dict[_KT, _VT]): def popitem(self, last: bool = True) -> tuple[_KT, _VT]: ... def move_to_end(self, key: _KT, last: bool = True) -> None: ... @@ -395,6 +397,7 @@ class OrderedDict(dict[_KT, _VT]): @overload def __ror__(self, value: dict[_T1, _T2], /) -> OrderedDict[_KT | _T1, _VT | _T2]: ... # type: ignore[misc] +@disjoint_base class defaultdict(dict[_KT, _VT]): default_factory: Callable[[], _VT] | None @overload diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index fb9f5990b6f2..61073fdb87a9 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -6,7 +6,7 @@ from builtins import type as Type # alias to avoid name clashes with fields nam from collections.abc import Callable, Iterable, Mapping from types import GenericAlias from typing import Any, Final, Generic, Literal, Protocol, TypeVar, overload, type_check_only -from typing_extensions import Never, TypeIs +from typing_extensions import Never, TypeIs, disjoint_base _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) @@ -169,6 +169,7 @@ else: class _DefaultFactory(Protocol[_T_co]): def __call__(self) -> _T_co: ... +@disjoint_base class Field(Generic[_T]): name: str type: Type[_T] | str | Any @@ -354,6 +355,7 @@ def is_dataclass(obj: object) -> TypeIs[DataclassInstance | type[DataclassInstan class FrozenInstanceError(AttributeError): ... +@disjoint_base class InitVar(Generic[_T]): type: Type[_T] def __init__(self, type: Type[_T]) -> None: ... diff --git a/stdlib/datetime.pyi b/stdlib/datetime.pyi index c54de6159b51..8a0536c006d5 100644 --- a/stdlib/datetime.pyi +++ b/stdlib/datetime.pyi @@ -2,7 +2,7 @@ import sys from abc import abstractmethod from time import struct_time from typing import ClassVar, Final, NoReturn, SupportsIndex, final, overload, type_check_only -from typing_extensions import CapsuleType, Self, TypeAlias, deprecated +from typing_extensions import CapsuleType, Self, TypeAlias, deprecated, disjoint_base if sys.version_info >= (3, 11): __all__ = ("date", "datetime", "time", "timedelta", "timezone", "tzinfo", "MINYEAR", "MAXYEAR", "UTC") @@ -51,6 +51,7 @@ class _IsoCalendarDate(tuple[int, int, int]): @property def weekday(self) -> int: ... +@disjoint_base class date: min: ClassVar[date] max: ClassVar[date] @@ -112,6 +113,7 @@ class date: def isoweekday(self) -> int: ... def isocalendar(self) -> _IsoCalendarDate: ... +@disjoint_base class time: min: ClassVar[time] max: ClassVar[time] @@ -191,6 +193,7 @@ class time: _Date: TypeAlias = date _Time: TypeAlias = time +@disjoint_base class timedelta: min: ClassVar[timedelta] max: ClassVar[timedelta] @@ -239,6 +242,7 @@ class timedelta: def __bool__(self) -> bool: ... def __hash__(self) -> int: ... +@disjoint_base class datetime(date): min: ClassVar[datetime] max: ClassVar[datetime] diff --git a/stdlib/decimal.pyi b/stdlib/decimal.pyi index b85c00080092..2e06c2d1b724 100644 --- a/stdlib/decimal.pyi +++ b/stdlib/decimal.pyi @@ -27,7 +27,7 @@ from _decimal import ( from collections.abc import Container, Sequence from types import TracebackType from typing import Any, ClassVar, Literal, NamedTuple, final, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base if sys.version_info >= (3, 14): from _decimal import IEEE_CONTEXT_MAX_BITS as IEEE_CONTEXT_MAX_BITS, IEEEContext as IEEEContext @@ -68,6 +68,7 @@ class Overflow(Inexact, Rounded): ... class Underflow(Inexact, Rounded, Subnormal): ... class FloatOperation(DecimalException, TypeError): ... +@disjoint_base class Decimal: def __new__(cls, value: _DecimalNew = "0", context: Context | None = None) -> Self: ... if sys.version_info >= (3, 14): @@ -173,6 +174,7 @@ class Decimal: def __deepcopy__(self, memo: Any, /) -> Self: ... def __format__(self, specifier: str, context: Context | None = None, /) -> str: ... +@disjoint_base class Context: # TODO: Context doesn't allow you to delete *any* attributes from instances of the class at runtime, # even settable attributes like `prec` and `rounding`, diff --git a/stdlib/fractions.pyi b/stdlib/fractions.pyi index e81fbaf5dad7..c24dbda264fb 100644 --- a/stdlib/fractions.pyi +++ b/stdlib/fractions.pyi @@ -3,7 +3,7 @@ from collections.abc import Callable from decimal import Decimal from numbers import Rational, Real from typing import Any, Literal, Protocol, SupportsIndex, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base _ComparableNum: TypeAlias = int | float | Decimal | Real @@ -13,6 +13,7 @@ __all__ = ["Fraction"] class _ConvertibleToIntegerRatio(Protocol): def as_integer_ratio(self) -> tuple[int | Rational, int | Rational]: ... +@disjoint_base class Fraction(Rational): @overload def __new__(cls, numerator: int | Rational = 0, denominator: int | Rational | None = None) -> Self: ... diff --git a/stdlib/functools.pyi b/stdlib/functools.pyi index e41eb4c2b65d..a803d81c9b25 100644 --- a/stdlib/functools.pyi +++ b/stdlib/functools.pyi @@ -4,7 +4,7 @@ from _typeshed import SupportsAllComparisons, SupportsItems from collections.abc import Callable, Hashable, Iterable, Sized from types import GenericAlias from typing import Any, Final, Generic, Literal, NamedTuple, TypedDict, TypeVar, final, overload, type_check_only -from typing_extensions import ParamSpec, Self, TypeAlias +from typing_extensions import ParamSpec, Self, TypeAlias, disjoint_base __all__ = [ "update_wrapper", @@ -150,7 +150,7 @@ else: def total_ordering(cls: type[_T]) -> type[_T]: ... def cmp_to_key(mycmp: Callable[[_T, _T], int]) -> Callable[[_T], SupportsAllComparisons]: ... - +@disjoint_base class partial(Generic[_T]): @property def func(self) -> Callable[..., _T]: ... diff --git a/stdlib/hmac.pyi b/stdlib/hmac.pyi index 300ed9eb26d8..ef55577fbf34 100644 --- a/stdlib/hmac.pyi +++ b/stdlib/hmac.pyi @@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer, SizedBuffer from collections.abc import Callable from types import ModuleType from typing import overload -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base _DigestMod: TypeAlias = str | Callable[[], _HashObject] | ModuleType @@ -18,7 +18,7 @@ digest_size: None def new(key: bytes | bytearray, msg: ReadableBuffer | None, digestmod: _DigestMod) -> HMAC: ... @overload def new(key: bytes | bytearray, *, digestmod: _DigestMod) -> HMAC: ... - +@disjoint_base class HMAC: digest_size: int block_size: int diff --git a/stdlib/inspect.pyi b/stdlib/inspect.pyi index f8ec6cad0160..eebf267ed912 100644 --- a/stdlib/inspect.pyi +++ b/stdlib/inspect.pyi @@ -26,7 +26,7 @@ from types import ( WrapperDescriptorType, ) from typing import Any, ClassVar, Final, Literal, NamedTuple, Protocol, TypeVar, overload, type_check_only -from typing_extensions import ParamSpec, Self, TypeAlias, TypeGuard, TypeIs, deprecated +from typing_extensions import ParamSpec, Self, TypeAlias, TypeGuard, TypeIs, deprecated, disjoint_base if sys.version_info >= (3, 14): from annotationlib import Format @@ -335,6 +335,7 @@ else: class _void: ... class _empty: ... +@disjoint_base class Signature: def __init__( self, parameters: Sequence[Parameter] | None = None, *, return_annotation: Any = ..., __validate_parameters__: bool = True @@ -415,6 +416,7 @@ if sys.version_info >= (3, 12): ) -> Literal["AGEN_CREATED", "AGEN_RUNNING", "AGEN_SUSPENDED", "AGEN_CLOSED"]: ... def getasyncgenlocals(agen: AsyncGeneratorType[Any, Any]) -> dict[str, Any]: ... +@disjoint_base class Parameter: def __init__(self, name: str, kind: _ParameterKind, *, default: Any = ..., annotation: Any = ...) -> None: ... empty = _empty @@ -446,6 +448,7 @@ class Parameter: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... +@disjoint_base class BoundArguments: arguments: OrderedDict[str, Any] @property diff --git a/stdlib/ipaddress.pyi b/stdlib/ipaddress.pyi index 6d49eb8bd94a..04e328957833 100644 --- a/stdlib/ipaddress.pyi +++ b/stdlib/ipaddress.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Iterable, Iterator from typing import Any, Final, Generic, Literal, TypeVar, overload -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base # Undocumented length constants IPV4LENGTH: Final = 32 @@ -114,6 +114,7 @@ class _BaseV4: @property def max_prefixlen(self) -> Literal[32]: ... +@disjoint_base class IPv4Address(_BaseV4, _BaseAddress): def __init__(self, address: object) -> None: ... @property @@ -165,6 +166,7 @@ class _BaseV6: @property def max_prefixlen(self) -> Literal[128]: ... +@disjoint_base class IPv6Address(_BaseV6, _BaseAddress): def __init__(self, address: object) -> None: ... @property diff --git a/stdlib/itertools.pyi b/stdlib/itertools.pyi index d0085dd7224d..fe4ccbdf8ae9 100644 --- a/stdlib/itertools.pyi +++ b/stdlib/itertools.pyi @@ -3,7 +3,7 @@ from _typeshed import MaybeNone from collections.abc import Callable, Iterable, Iterator from types import GenericAlias from typing import Any, Generic, Literal, SupportsComplex, SupportsFloat, SupportsIndex, SupportsInt, TypeVar, overload -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base _T = TypeVar("_T") _S = TypeVar("_S") @@ -27,6 +27,7 @@ _Predicate: TypeAlias = Callable[[_T], object] # Technically count can take anything that implements a number protocol and has an add method # but we can't enforce the add method +@disjoint_base class count(Generic[_N]): @overload def __new__(cls) -> count[int]: ... @@ -37,11 +38,13 @@ class count(Generic[_N]): def __next__(self) -> _N: ... def __iter__(self) -> Self: ... +@disjoint_base class cycle(Generic[_T]): def __new__(cls, iterable: Iterable[_T], /) -> Self: ... def __next__(self) -> _T: ... def __iter__(self) -> Self: ... +@disjoint_base class repeat(Generic[_T]): @overload def __new__(cls, object: _T) -> Self: ... @@ -51,6 +54,7 @@ class repeat(Generic[_T]): def __iter__(self) -> Self: ... def __length_hint__(self) -> int: ... +@disjoint_base class accumulate(Generic[_T]): @overload def __new__(cls, iterable: Iterable[_T], func: None = None, *, initial: _T | None = ...) -> Self: ... @@ -59,6 +63,7 @@ class accumulate(Generic[_T]): def __iter__(self) -> Self: ... def __next__(self) -> _T: ... +@disjoint_base class chain(Generic[_T]): def __new__(cls, *iterables: Iterable[_T]) -> Self: ... def __next__(self) -> _T: ... @@ -68,21 +73,25 @@ class chain(Generic[_T]): def from_iterable(cls: type[Any], iterable: Iterable[Iterable[_S]], /) -> chain[_S]: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... +@disjoint_base class compress(Generic[_T]): def __new__(cls, data: Iterable[_T], selectors: Iterable[Any]) -> Self: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... +@disjoint_base class dropwhile(Generic[_T]): def __new__(cls, predicate: _Predicate[_T], iterable: Iterable[_T], /) -> Self: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... +@disjoint_base class filterfalse(Generic[_T]): def __new__(cls, function: _Predicate[_T] | None, iterable: Iterable[_T], /) -> Self: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... +@disjoint_base class groupby(Generic[_T_co, _S_co]): @overload def __new__(cls, iterable: Iterable[_T1], key: None = None) -> groupby[_T1, _T1]: ... @@ -91,6 +100,7 @@ class groupby(Generic[_T_co, _S_co]): def __iter__(self) -> Self: ... def __next__(self) -> tuple[_T_co, Iterator[_S_co]]: ... +@disjoint_base class islice(Generic[_T]): @overload def __new__(cls, iterable: Iterable[_T], stop: int | None, /) -> Self: ... @@ -99,18 +109,20 @@ class islice(Generic[_T]): def __iter__(self) -> Self: ... def __next__(self) -> _T: ... +@disjoint_base class starmap(Generic[_T_co]): def __new__(cls, function: Callable[..., _T], iterable: Iterable[Iterable[Any]], /) -> starmap[_T]: ... def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... +@disjoint_base class takewhile(Generic[_T]): def __new__(cls, predicate: _Predicate[_T], iterable: Iterable[_T], /) -> Self: ... def __iter__(self) -> Self: ... def __next__(self) -> _T: ... def tee(iterable: Iterable[_T], n: int = 2, /) -> tuple[Iterator[_T], ...]: ... - +@disjoint_base class zip_longest(Generic[_T_co]): # one iterable (fillvalue doesn't matter) @overload @@ -189,6 +201,7 @@ class zip_longest(Generic[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... +@disjoint_base class product(Generic[_T_co]): @overload def __new__(cls, iter1: Iterable[_T1], /) -> product[tuple[_T1]]: ... @@ -274,6 +287,7 @@ class product(Generic[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... +@disjoint_base class permutations(Generic[_T_co]): @overload def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> permutations[tuple[_T, _T]]: ... @@ -288,6 +302,7 @@ class permutations(Generic[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... +@disjoint_base class combinations(Generic[_T_co]): @overload def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> combinations[tuple[_T, _T]]: ... @@ -302,6 +317,7 @@ class combinations(Generic[_T_co]): def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... +@disjoint_base class combinations_with_replacement(Generic[_T_co]): @overload def __new__(cls, iterable: Iterable[_T], r: Literal[2]) -> combinations_with_replacement[tuple[_T, _T]]: ... @@ -317,12 +333,14 @@ class combinations_with_replacement(Generic[_T_co]): def __next__(self) -> _T_co: ... if sys.version_info >= (3, 10): + @disjoint_base class pairwise(Generic[_T_co]): def __new__(cls, iterable: Iterable[_T], /) -> pairwise[tuple[_T, _T]]: ... def __iter__(self) -> Self: ... def __next__(self) -> _T_co: ... if sys.version_info >= (3, 12): + @disjoint_base class batched(Generic[_T_co]): if sys.version_info >= (3, 13): def __new__(cls, iterable: Iterable[_T_co], n: int, *, strict: bool = False) -> Self: ... diff --git a/stdlib/mmap.pyi b/stdlib/mmap.pyi index 261a2bfdfc44..a8e4660896e3 100644 --- a/stdlib/mmap.pyi +++ b/stdlib/mmap.pyi @@ -3,7 +3,7 @@ import sys from _typeshed import ReadableBuffer, Unused from collections.abc import Iterator from typing import Final, Literal, NoReturn, overload -from typing_extensions import Self +from typing_extensions import Self, disjoint_base ACCESS_DEFAULT: Final = 0 ACCESS_READ: Final = 1 @@ -31,6 +31,7 @@ if sys.platform != "win32": PAGESIZE: Final[int] +@disjoint_base class mmap: if sys.platform == "win32": def __init__(self, fileno: int, length: int, tagname: str | None = None, access: int = 0, offset: int = 0) -> None: ... diff --git a/stdlib/multiprocessing/managers.pyi b/stdlib/multiprocessing/managers.pyi index b0ccac41b925..0ce74f991d7c 100644 --- a/stdlib/multiprocessing/managers.pyi +++ b/stdlib/multiprocessing/managers.pyi @@ -15,7 +15,7 @@ from collections.abc import ( ) from types import GenericAlias, TracebackType from typing import Any, AnyStr, ClassVar, Generic, SupportsIndex, TypeVar, overload -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base from . import pool from .connection import Connection, _Address @@ -37,6 +37,7 @@ class Namespace: _Namespace: TypeAlias = Namespace +@disjoint_base class Token: typeid: str | bytes | None address: _Address | None diff --git a/stdlib/pathlib/__init__.pyi b/stdlib/pathlib/__init__.pyi index 4858f8db1ed0..db56005b40cb 100644 --- a/stdlib/pathlib/__init__.pyi +++ b/stdlib/pathlib/__init__.pyi @@ -16,7 +16,7 @@ from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWra from os import PathLike, stat_result from types import GenericAlias, TracebackType from typing import IO, Any, BinaryIO, ClassVar, Literal, TypeVar, overload -from typing_extensions import Never, Self, deprecated +from typing_extensions import Never, Self, deprecated, disjoint_base _PathT = TypeVar("_PathT", bound=PurePath) @@ -28,6 +28,7 @@ if sys.version_info >= (3, 14): if sys.version_info >= (3, 13): __all__ += ["UnsupportedOperation"] +@disjoint_base class PurePath(PathLike[str]): if sys.version_info >= (3, 13): parser: ClassVar[types.ModuleType] diff --git a/stdlib/pickletools.pyi b/stdlib/pickletools.pyi index 23e9cbaa2c20..aaaa105fbe28 100644 --- a/stdlib/pickletools.pyi +++ b/stdlib/pickletools.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Callable, Iterator, MutableMapping from typing import IO, Any, Final -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base __all__ = ["dis", "genops", "optimize"] @@ -14,6 +14,7 @@ TAKEN_FROM_ARGUMENT4: Final = -3 TAKEN_FROM_ARGUMENT4U: Final = -4 TAKEN_FROM_ARGUMENT8U: Final = -5 +@disjoint_base class ArgumentDescriptor: name: str n: int @@ -117,6 +118,7 @@ def read_long4(f: IO[bytes]) -> int: ... long4: ArgumentDescriptor +@disjoint_base class StackObject: name: str obtype: type[Any] | tuple[type[Any], ...] @@ -142,6 +144,7 @@ anyobject: StackObject markobject: StackObject stackslice: StackObject +@disjoint_base class OpcodeInfo: name: str code: str diff --git a/stdlib/socket.pyi b/stdlib/socket.pyi index f1fdc9097e4a..dde9d23ca3bb 100644 --- a/stdlib/socket.pyi +++ b/stdlib/socket.pyi @@ -137,7 +137,7 @@ from collections.abc import Iterable from enum import IntEnum, IntFlag from io import BufferedReader, BufferedRWPair, BufferedWriter, IOBase, RawIOBase, TextIOWrapper from typing import Any, Final, Literal, Protocol, SupportsIndex, overload, type_check_only -from typing_extensions import Self +from typing_extensions import Self, disjoint_base __all__ = [ "fromfd", @@ -1299,6 +1299,7 @@ class _SendableFile(Protocol): # def mode(self) -> str: ... # def fileno(self) -> int: ... +@disjoint_base class socket(_socket.socket): def __init__( self, family: AddressFamily | int = -1, type: SocketKind | int = -1, proto: int = -1, fileno: int | None = None diff --git a/stdlib/sqlite3/__init__.pyi b/stdlib/sqlite3/__init__.pyi index bcfea3a13021..6b0f1ba94910 100644 --- a/stdlib/sqlite3/__init__.pyi +++ b/stdlib/sqlite3/__init__.pyi @@ -63,7 +63,7 @@ from sqlite3.dbapi2 import ( ) from types import TracebackType from typing import Any, Literal, Protocol, SupportsIndex, TypeVar, final, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base if sys.version_info < (3, 14): from sqlite3.dbapi2 import version_info as version_info @@ -268,6 +268,7 @@ class OperationalError(DatabaseError): ... class ProgrammingError(DatabaseError): ... class Warning(Exception): ... +@disjoint_base class Connection: @property def DataError(self) -> type[DataError]: ... @@ -405,6 +406,7 @@ class Connection: self, type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None, / ) -> Literal[False]: ... +@disjoint_base class Cursor: arraysize: int @property @@ -436,6 +438,7 @@ class Cursor: class PrepareProtocol: def __init__(self, *args: object, **kwargs: object) -> None: ... +@disjoint_base class Row(Sequence[Any]): def __new__(cls, cursor: Cursor, data: tuple[Any, ...], /) -> Self: ... def keys(self) -> list[str]: ... diff --git a/stdlib/statistics.pyi b/stdlib/statistics.pyi index 6d7d3fbb4956..30e7e72e46e0 100644 --- a/stdlib/statistics.pyi +++ b/stdlib/statistics.pyi @@ -4,7 +4,7 @@ from collections.abc import Callable, Hashable, Iterable, Sequence from decimal import Decimal from fractions import Fraction from typing import Literal, NamedTuple, SupportsFloat, SupportsIndex, TypeVar -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base __all__ = [ "StatisticsError", @@ -77,7 +77,7 @@ def quantiles( ) -> list[_NumberT]: ... def stdev(data: Iterable[_NumberT], xbar: _NumberT | None = None) -> _NumberT: ... def variance(data: Iterable[_NumberT], xbar: _NumberT | None = None) -> _NumberT: ... - +@disjoint_base class NormalDist: def __init__(self, mu: float = 0.0, sigma: float = 1.0) -> None: ... @property diff --git a/stdlib/tarfile.pyi b/stdlib/tarfile.pyi index 4e394409bbe0..88279f3d365b 100644 --- a/stdlib/tarfile.pyi +++ b/stdlib/tarfile.pyi @@ -7,7 +7,7 @@ from collections.abc import Callable, Iterable, Iterator, Mapping from gzip import _ReadableFileobj as _GzipReadableFileobj, _WritableFileobj as _GzipWritableFileobj from types import TracebackType from typing import IO, ClassVar, Final, Literal, Protocol, overload, type_check_only -from typing_extensions import Self, TypeAlias, deprecated +from typing_extensions import Self, TypeAlias, deprecated, disjoint_base if sys.version_info >= (3, 14): from compression.zstd import ZstdDict @@ -742,7 +742,7 @@ class LinkFallbackError(FilterError): def fully_trusted_filter(member: TarInfo, dest_path: str) -> TarInfo: ... def tar_filter(member: TarInfo, dest_path: str) -> TarInfo: ... def data_filter(member: TarInfo, dest_path: str) -> TarInfo: ... - +@disjoint_base class TarInfo: name: str path: str diff --git a/stdlib/traceback.pyi b/stdlib/traceback.pyi index 4553dbd08384..f1290d7d2689 100644 --- a/stdlib/traceback.pyi +++ b/stdlib/traceback.pyi @@ -3,7 +3,7 @@ from _typeshed import SupportsWrite, Unused from collections.abc import Generator, Iterable, Iterator, Mapping from types import FrameType, TracebackType from typing import Any, ClassVar, Literal, overload -from typing_extensions import Self, TypeAlias, deprecated +from typing_extensions import Self, TypeAlias, deprecated, disjoint_base __all__ = [ "extract_stack", @@ -244,6 +244,7 @@ class TracebackException: if sys.version_info >= (3, 11): def print(self, *, file: SupportsWrite[str] | None = None, chain: bool = True) -> None: ... +@disjoint_base class FrameSummary: if sys.version_info >= (3, 11): def __init__( diff --git a/stdlib/tracemalloc.pyi b/stdlib/tracemalloc.pyi index 05d98ae127d8..247ed699d237 100644 --- a/stdlib/tracemalloc.pyi +++ b/stdlib/tracemalloc.pyi @@ -2,7 +2,7 @@ import sys from _tracemalloc import * from collections.abc import Sequence from typing import Any, SupportsIndex, overload -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base def get_object_traceback(obj: object) -> Traceback | None: ... def take_snapshot() -> Snapshot: ... @@ -31,6 +31,7 @@ class Filter(BaseFilter): domain: int | None = None, ) -> None: ... +@disjoint_base class Statistic: count: int size: int @@ -39,6 +40,7 @@ class Statistic: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... +@disjoint_base class StatisticDiff: count: int count_diff: int @@ -51,6 +53,7 @@ class StatisticDiff: _FrameTuple: TypeAlias = tuple[str, int] +@disjoint_base class Frame: @property def filename(self) -> str: ... @@ -71,6 +74,7 @@ class Frame: _TraceTuple: TypeAlias = tuple[int, int, Sequence[_FrameTuple], int | None] | tuple[int, int, Sequence[_FrameTuple]] +@disjoint_base class Trace: @property def domain(self) -> int: ... @@ -82,6 +86,7 @@ class Trace: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... +@disjoint_base class Traceback(Sequence[Frame]): @property def total_nframe(self) -> int | None: ... diff --git a/stdlib/types.pyi b/stdlib/types.pyi index 44bd3eeb3f53..a6be9b14b6be 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -17,7 +17,7 @@ from collections.abc import ( ) from importlib.machinery import ModuleSpec from typing import Any, ClassVar, Literal, TypeVar, final, overload -from typing_extensions import ParamSpec, Self, TypeAliasType, TypeVarTuple, deprecated +from typing_extensions import ParamSpec, Self, TypeAliasType, TypeVarTuple, deprecated, disjoint_base if sys.version_info >= (3, 14): from _typeshed import AnnotateFunc @@ -331,6 +331,7 @@ class MappingProxyType(Mapping[_KT, _VT_co]): def __or__(self, value: Mapping[_T1, _T2], /) -> dict[_KT | _T1, _VT_co | _T2]: ... def __ror__(self, value: Mapping[_T1, _T2], /) -> dict[_KT | _T1, _VT_co | _T2]: ... +@disjoint_base class SimpleNamespace: __hash__: ClassVar[None] # type: ignore[assignment] if sys.version_info >= (3, 13): @@ -345,6 +346,7 @@ class SimpleNamespace: if sys.version_info >= (3, 13): def __replace__(self, **kwargs: Any) -> Self: ... +@disjoint_base class ModuleType: __name__: str __file__: str | None @@ -661,7 +663,7 @@ _P = ParamSpec("_P") def coroutine(func: Callable[_P, Generator[Any, Any, _R]]) -> Callable[_P, Awaitable[_R]]: ... @overload def coroutine(func: _Fn) -> _Fn: ... - +@disjoint_base class GenericAlias: @property def __origin__(self) -> type | TypeAliasType: ... diff --git a/stdlib/uuid.pyi b/stdlib/uuid.pyi index 0aa2f76d40cc..c575a36641b7 100644 --- a/stdlib/uuid.pyi +++ b/stdlib/uuid.pyi @@ -2,7 +2,7 @@ import builtins import sys from enum import Enum from typing import Final -from typing_extensions import LiteralString, TypeAlias +from typing_extensions import LiteralString, TypeAlias, disjoint_base _FieldsType: TypeAlias = tuple[int, int, int, int, int, int] @@ -11,6 +11,7 @@ class SafeUUID(Enum): unsafe = -1 unknown = None +@disjoint_base class UUID: def __init__( self, diff --git a/stdlib/weakref.pyi b/stdlib/weakref.pyi index 334fab7e7468..e3fe54517557 100644 --- a/stdlib/weakref.pyi +++ b/stdlib/weakref.pyi @@ -4,7 +4,7 @@ from _weakrefset import WeakSet as WeakSet from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping from types import GenericAlias from typing import Any, ClassVar, Generic, TypeVar, final, overload -from typing_extensions import ParamSpec, Self +from typing_extensions import ParamSpec, Self, disjoint_base __all__ = [ "ref", @@ -52,6 +52,7 @@ class ProxyType(Generic[_T]): # "weakproxy" def __getattr__(self, attr: str) -> Any: ... __hash__: ClassVar[None] # type: ignore[assignment] +@disjoint_base class ReferenceType(Generic[_T]): # "weakref" __callback__: Callable[[Self], Any] def __new__(cls, o: _T, callback: Callable[[Self], Any] | None = ..., /) -> Self: ... @@ -64,6 +65,7 @@ ref = ReferenceType # everything below here is implemented in weakref.py +@disjoint_base class WeakMethod(ref[_CallableT]): def __new__(cls, meth: _CallableT, callback: Callable[[Self], Any] | None = None) -> Self: ... def __call__(self) -> _CallableT | None: ... @@ -129,6 +131,7 @@ class WeakValueDictionary(MutableMapping[_KT, _VT]): @overload def __ior__(self, other: Iterable[tuple[_KT, _VT]]) -> Self: ... +@disjoint_base class KeyedRef(ref[_T], Generic[_KT, _T]): key: _KT def __new__(type, ob: _T, callback: Callable[[Self], Any], key: _KT) -> Self: ... diff --git a/stdlib/xml/dom/expatbuilder.pyi b/stdlib/xml/dom/expatbuilder.pyi index 228ad07e15ad..ab1276992c57 100644 --- a/stdlib/xml/dom/expatbuilder.pyi +++ b/stdlib/xml/dom/expatbuilder.pyi @@ -1,6 +1,6 @@ from _typeshed import ReadableBuffer, SupportsRead from typing import Any, NoReturn -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base from xml.dom.minidom import Document, DocumentFragment, DOMImplementation, Element, Node, TypeInfo from xml.dom.xmlbuilder import DOMBuilderFilter, Options from xml.parsers.expat import XMLParserType @@ -16,6 +16,7 @@ FILTER_SKIP = DOMBuilderFilter.FILTER_SKIP FILTER_INTERRUPT = DOMBuilderFilter.FILTER_INTERRUPT theDOMImplementation: DOMImplementation +@disjoint_base class ElementInfo: tagName: str def __init__(self, tagName: str, model: _Model | None = None) -> None: ... @@ -65,12 +66,14 @@ class ExpatBuilder: def attlist_decl_handler(self, elem: str, name: str, type: str, default: str | None, required: bool) -> None: ... def xml_decl_handler(self, version: str, encoding: str | None, standalone: int) -> None: ... +@disjoint_base class FilterVisibilityController: filter: DOMBuilderFilter def __init__(self, filter: DOMBuilderFilter) -> None: ... def startContainer(self, node: Node) -> int: ... def acceptNode(self, node: Node) -> int: ... +@disjoint_base class FilterCrutch: def __init__(self, builder: ExpatBuilder) -> None: ... diff --git a/stdlib/xml/dom/minidom.pyi b/stdlib/xml/dom/minidom.pyi index b9da9f3558ff..4a4de5099a2a 100644 --- a/stdlib/xml/dom/minidom.pyi +++ b/stdlib/xml/dom/minidom.pyi @@ -4,7 +4,7 @@ from _typeshed import Incomplete, ReadableBuffer, SupportsRead, SupportsWrite from collections.abc import Iterable, Sequence from types import TracebackType from typing import Any, ClassVar, Generic, Literal, NoReturn, Protocol, TypeVar, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base from xml.dom.minicompat import EmptyNodeList, NodeList from xml.dom.xmlbuilder import DocumentLS, DOMImplementationLS from xml.sax.xmlreader import XMLReader @@ -187,6 +187,7 @@ class DocumentFragment(Node): _AttrChildrenVar = TypeVar("_AttrChildrenVar", bound=_AttrChildren) _AttrChildrenPlusFragment = TypeVar("_AttrChildrenPlusFragment", bound=_AttrChildren | DocumentFragment) +@disjoint_base class Attr(Node): nodeType: ClassVar[Literal[2]] nodeName: str # same as Attr.name @@ -230,6 +231,7 @@ class Attr(Node): # In the DOM, this interface isn't specific to Attr, but our implementation is # because that's the only place we use it. +@disjoint_base class NamedNodeMap: def __init__(self, attrs: dict[str, Attr], attrsNS: dict[_NSName, Attr], ownerElement: Element) -> None: ... @property @@ -261,6 +263,7 @@ class NamedNodeMap: AttributeList = NamedNodeMap +@disjoint_base class TypeInfo: namespace: str | None name: str | None @@ -269,6 +272,7 @@ class TypeInfo: _ElementChildrenVar = TypeVar("_ElementChildrenVar", bound=_ElementChildren) _ElementChildrenPlusFragment = TypeVar("_ElementChildrenPlusFragment", bound=_ElementChildren | DocumentFragment) +@disjoint_base class Element(Node): nodeType: ClassVar[Literal[1]] nodeName: str # same as Element.tagName @@ -346,6 +350,7 @@ class Childless: def normalize(self) -> None: ... def replaceChild(self, newChild: _NodesThatAreChildren | DocumentFragment, oldChild: _NodesThatAreChildren) -> NoReturn: ... +@disjoint_base class ProcessingInstruction(Childless, Node): nodeType: ClassVar[Literal[7]] nodeName: str # same as ProcessingInstruction.target @@ -372,6 +377,7 @@ class ProcessingInstruction(Childless, Node): def __init__(self, target: str, data: str) -> None: ... def writexml(self, writer: SupportsWrite[str], indent: str = "", addindent: str = "", newl: str = "") -> None: ... +@disjoint_base class CharacterData(Childless, Node): nodeValue: str attributes: None @@ -459,6 +465,7 @@ class CDATASection(Text): def writexml(self, writer: SupportsWrite[str], indent: str = "", addindent: str = "", newl: str = "") -> None: ... +@disjoint_base class ReadOnlySequentialNamedNodeMap(Generic[_N]): def __init__(self, seq: Sequence[_N] = ()) -> None: ... def __len__(self) -> int: ... @@ -473,6 +480,7 @@ class ReadOnlySequentialNamedNodeMap(Generic[_N]): @property def length(self) -> int: ... +@disjoint_base class Identified: publicId: str | None systemId: str | None @@ -564,6 +572,7 @@ class DOMImplementation(DOMImplementationLS): def createDocumentType(self, qualifiedName: str | None, publicId: str | None, systemId: str | None) -> DocumentType: ... def getInterface(self, feature: str) -> Self | None: ... +@disjoint_base class ElementInfo: tagName: str def __init__(self, name: str) -> None: ... @@ -576,6 +585,7 @@ class ElementInfo: _DocumentChildrenPlusFragment = TypeVar("_DocumentChildrenPlusFragment", bound=_DocumentChildren | DocumentFragment) +@disjoint_base class Document(Node, DocumentLS): nodeType: ClassVar[Literal[9]] nodeName: Literal["#document"] diff --git a/stdlib/xml/dom/xmlbuilder.pyi b/stdlib/xml/dom/xmlbuilder.pyi index 6fb18bbc4eda..5267c65414ab 100644 --- a/stdlib/xml/dom/xmlbuilder.pyi +++ b/stdlib/xml/dom/xmlbuilder.pyi @@ -1,5 +1,6 @@ from _typeshed import SupportsRead from typing import Any, Literal, NoReturn +from typing_extensions import disjoint_base from xml.dom.minidom import Document, Node, _DOMErrorHandler __all__ = ["DOMBuilder", "DOMEntityResolver", "DOMInputSource"] @@ -43,9 +44,11 @@ class DOMBuilder: def parse(self, input: DOMInputSource) -> Document: ... def parseWithContext(self, input: DOMInputSource, cnode: Node, action: Literal[1, 2, 3, 4]) -> NoReturn: ... +@disjoint_base class DOMEntityResolver: def resolveEntity(self, publicId: str | None, systemId: str) -> DOMInputSource: ... +@disjoint_base class DOMInputSource: byteStream: SupportsRead[bytes] | None characterStream: SupportsRead[str] | None diff --git a/stdlib/xml/etree/ElementTree.pyi b/stdlib/xml/etree/ElementTree.pyi index 1d7e1725dd8e..489ed188a203 100644 --- a/stdlib/xml/etree/ElementTree.pyi +++ b/stdlib/xml/etree/ElementTree.pyi @@ -3,7 +3,7 @@ from _collections_abc import dict_keys from _typeshed import FileDescriptorOrPath, ReadableBuffer, SupportsRead, SupportsWrite from collections.abc import Callable, Generator, ItemsView, Iterable, Iterator, Mapping, Sequence from typing import Any, Final, Generic, Literal, Protocol, SupportsIndex, TypeVar, overload, type_check_only -from typing_extensions import TypeAlias, TypeGuard, deprecated +from typing_extensions import TypeAlias, TypeGuard, deprecated, disjoint_base from xml.parsers.expat import XMLParserType __all__ = [ @@ -86,6 +86,7 @@ _CallableElement: TypeAlias = Element[_ElementCallable] _Tag = TypeVar("_Tag", default=str, bound=str | _ElementCallable) _OtherTag = TypeVar("_OtherTag", default=str, bound=str | _ElementCallable) +@disjoint_base class Element(Generic[_Tag]): tag: _Tag attrib: dict[str, str] @@ -288,6 +289,7 @@ def fromstringlist(sequence: Sequence[str | ReadableBuffer], parser: XMLParser | # elementfactories. _ElementFactory: TypeAlias = Callable[[Any, dict[Any, Any]], Element] +@disjoint_base class TreeBuilder: # comment_factory can take None because passing None to Comment is not an error def __init__( @@ -353,6 +355,7 @@ _E = TypeVar("_E", default=Element) # The default target is TreeBuilder, which returns Element. # C14NWriterTarget does not implement a close method, so using it results # in a type of XMLParser[None]. +@disjoint_base class XMLParser(Generic[_E]): parser: XMLParserType target: _Target diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index 73e3a92fd0e2..d71067535e91 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -6,7 +6,7 @@ from io import TextIOWrapper from os import PathLike from types import TracebackType from typing import IO, Final, Literal, Protocol, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base __all__ = [ "BadZipFile", @@ -271,6 +271,7 @@ class PyZipFile(ZipFile): ) -> None: ... def writepy(self, pathname: str, basename: str = "", filterfunc: Callable[[str], bool] | None = None) -> None: ... +@disjoint_base class ZipInfo: filename: str date_time: _DateTuple diff --git a/stdlib/zoneinfo/__init__.pyi b/stdlib/zoneinfo/__init__.pyi index e9f54fbf2a26..b7433f835f83 100644 --- a/stdlib/zoneinfo/__init__.pyi +++ b/stdlib/zoneinfo/__init__.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Iterable from datetime import datetime, timedelta, tzinfo -from typing_extensions import Self +from typing_extensions import Self, disjoint_base from zoneinfo._common import ZoneInfoNotFoundError as ZoneInfoNotFoundError, _IOBytes from zoneinfo._tzpath import ( TZPATH as TZPATH, @@ -12,6 +12,7 @@ from zoneinfo._tzpath import ( __all__ = ["ZoneInfo", "reset_tzpath", "available_timezones", "TZPATH", "ZoneInfoNotFoundError", "InvalidTZPathWarning"] +@disjoint_base class ZoneInfo(tzinfo): @property def key(self) -> str: ... From 612bb3b2c1753d0ded6940cc7b451d21dd4f823d Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 20 Aug 2025 15:10:51 -0700 Subject: [PATCH 02/21] 3.14 stubtest --- stdlib/asyncio/graph.pyi | 4 ++-- stdlib/compression/zstd/__init__.pyi | 1 + stdlib/pathlib/__init__.pyi | 3 +++ stdlib/typing.pyi | 1 + 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/stdlib/asyncio/graph.pyi b/stdlib/asyncio/graph.pyi index cb2cf0174995..69d23c021552 100644 --- a/stdlib/asyncio/graph.pyi +++ b/stdlib/asyncio/graph.pyi @@ -6,11 +6,11 @@ from typing import Any, overload __all__ = ("capture_call_graph", "format_call_graph", "print_call_graph", "FrameCallGraphEntry", "FutureCallGraph") -@dataclass(frozen=True) +@dataclass(frozen=True, slots=True) class FrameCallGraphEntry: frame: FrameType -@dataclass(frozen=True) +@dataclass(frozen=True, slots=True) class FutureCallGraph: future: Future[Any] call_stack: tuple[FrameCallGraphEntry, ...] diff --git a/stdlib/compression/zstd/__init__.pyi b/stdlib/compression/zstd/__init__.pyi index 24a9633c488e..6cc76b470f7d 100644 --- a/stdlib/compression/zstd/__init__.pyi +++ b/stdlib/compression/zstd/__init__.pyi @@ -35,6 +35,7 @@ zstd_version_info: Final[tuple[int, int, int]] COMPRESSION_LEVEL_DEFAULT: Final = _zstd.ZSTD_CLEVEL_DEFAULT class FrameInfo: + __slots__ = "decompressed_size", "dictionary_id" decompressed_size: int dictionary_id: int def __init__(self, decompressed_size: int, dictionary_id: int) -> None: ... diff --git a/stdlib/pathlib/__init__.pyi b/stdlib/pathlib/__init__.pyi index db56005b40cb..53073e9d1226 100644 --- a/stdlib/pathlib/__init__.pyi +++ b/stdlib/pathlib/__init__.pyi @@ -113,6 +113,9 @@ class PurePosixPath(PurePath): ... class PureWindowsPath(PurePath): ... class Path(PurePath): + if sys.version_info >= (3, 14): + __slots__ = ("_info",) + if sys.version_info >= (3, 12): def __new__(cls, *args: StrPath, **kwargs: Unused) -> Self: ... # pyright: ignore[reportInconsistentConstructor] else: diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 7d048a13c288..1cba148ecb17 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -703,6 +703,7 @@ class MutableSet(AbstractSet[_T]): def __isub__(self, it: AbstractSet[Any]) -> typing_extensions.Self: ... class MappingView(Sized): + __slots__ = ("_mapping",) def __init__(self, mapping: Sized) -> None: ... # undocumented def __len__(self) -> int: ... From 3f56c9b14b7f59601078807028c0443915f7b841 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 20 Aug 2025 15:28:40 -0700 Subject: [PATCH 03/21] stubtest fixes --- stdlib/_io.pyi | 83 ++++++++++++++++++++++------------ stdlib/ast.pyi | 25 +++++++---- stdlib/codecs.pyi | 88 +++++++++++++++++++++++++------------ stdlib/crypt.pyi | 8 +++- stdlib/dis.pyi | 72 ++++++++++++++++-------------- stdlib/enum.pyi | 43 +++++++++++++----- stdlib/inspect.pyi | 83 +++++++++++++++++++++++----------- stdlib/logging/config.pyi | 21 ++++++--- stdlib/platform.pyi | 22 +++++++--- stdlib/sre_constants.pyi | 15 +++++-- stdlib/ssl.pyi | 47 ++++++++++++++++---- stdlib/tkinter/__init__.pyi | 8 +++- stdlib/tokenize.pyi | 15 +++++-- stdlib/turtle.pyi | 42 ++++++++++++------ stdlib/types.pyi | 38 ++++++++++------ stdlib/unittest/mock.pyi | 85 +++++++++++++++++++++++++---------- 16 files changed, 481 insertions(+), 214 deletions(-) diff --git a/stdlib/_io.pyi b/stdlib/_io.pyi index d1c2de99f3cb..aac9a196c3c0 100644 --- a/stdlib/_io.pyi +++ b/stdlib/_io.pyi @@ -19,33 +19,62 @@ def open_code(path: str) -> IO[bytes]: ... BlockingIOError = builtins.BlockingIOError -@disjoint_base -class _IOBase: - def __iter__(self) -> Iterator[bytes]: ... - def __next__(self) -> bytes: ... - def __enter__(self) -> Self: ... - def __exit__( - self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None - ) -> None: ... - def close(self) -> None: ... - def fileno(self) -> int: ... - def flush(self) -> None: ... - def isatty(self) -> bool: ... - def readable(self) -> bool: ... - read: Callable[..., Any] - def readlines(self, hint: int = -1, /) -> list[bytes]: ... - def seek(self, offset: int, whence: int = 0, /) -> int: ... - def seekable(self) -> bool: ... - def tell(self) -> int: ... - def truncate(self, size: int | None = None, /) -> int: ... - def writable(self) -> bool: ... - write: Callable[..., Any] - def writelines(self, lines: Iterable[ReadableBuffer], /) -> None: ... - def readline(self, size: int | None = -1, /) -> bytes: ... - def __del__(self) -> None: ... - @property - def closed(self) -> bool: ... - def _checkClosed(self) -> None: ... # undocumented +if sys.version_info >= (3, 12): + @disjoint_base + class _IOBase: + def __iter__(self) -> Iterator[bytes]: ... + def __next__(self) -> bytes: ... + def __enter__(self) -> Self: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: ... + def close(self) -> None: ... + def fileno(self) -> int: ... + def flush(self) -> None: ... + def isatty(self) -> bool: ... + def readable(self) -> bool: ... + read: Callable[..., Any] + def readlines(self, hint: int = -1, /) -> list[bytes]: ... + def seek(self, offset: int, whence: int = 0, /) -> int: ... + def seekable(self) -> bool: ... + def tell(self) -> int: ... + def truncate(self, size: int | None = None, /) -> int: ... + def writable(self) -> bool: ... + write: Callable[..., Any] + def writelines(self, lines: Iterable[ReadableBuffer], /) -> None: ... + def readline(self, size: int | None = -1, /) -> bytes: ... + def __del__(self) -> None: ... + @property + def closed(self) -> bool: ... + def _checkClosed(self) -> None: ... # undocumented + +else: + class _IOBase: + def __iter__(self) -> Iterator[bytes]: ... + def __next__(self) -> bytes: ... + def __enter__(self) -> Self: ... + def __exit__( + self, exc_type: type[BaseException] | None, exc_val: BaseException | None, exc_tb: TracebackType | None + ) -> None: ... + def close(self) -> None: ... + def fileno(self) -> int: ... + def flush(self) -> None: ... + def isatty(self) -> bool: ... + def readable(self) -> bool: ... + read: Callable[..., Any] + def readlines(self, hint: int = -1, /) -> list[bytes]: ... + def seek(self, offset: int, whence: int = 0, /) -> int: ... + def seekable(self) -> bool: ... + def tell(self) -> int: ... + def truncate(self, size: int | None = None, /) -> int: ... + def writable(self) -> bool: ... + write: Callable[..., Any] + def writelines(self, lines: Iterable[ReadableBuffer], /) -> None: ... + def readline(self, size: int | None = -1, /) -> bytes: ... + def __del__(self) -> None: ... + @property + def closed(self) -> bool: ... + def _checkClosed(self) -> None: ... # undocumented class _RawIOBase(_IOBase): def readall(self) -> bytes: ... diff --git a/stdlib/ast.pyi b/stdlib/ast.pyi index 5f82156c2c40..89171623c024 100644 --- a/stdlib/ast.pyi +++ b/stdlib/ast.pyi @@ -30,17 +30,24 @@ class _Attributes(TypedDict, Generic[_EndPositionT], total=False): # The various AST classes are implemented in C, and imported from _ast at runtime, # but they consider themselves to live in the ast module, # so we'll define the stubs in this file. -@disjoint_base -class AST: - if sys.version_info >= (3, 10): +if sys.version_info >= (3, 12): + @disjoint_base + class AST: __match_args__ = () - _attributes: ClassVar[tuple[str, ...]] - _fields: ClassVar[tuple[str, ...]] - if sys.version_info >= (3, 13): - _field_types: ClassVar[dict[str, Any]] + _attributes: ClassVar[tuple[str, ...]] + _fields: ClassVar[tuple[str, ...]] + if sys.version_info >= (3, 13): + _field_types: ClassVar[dict[str, Any]] - if sys.version_info >= (3, 14): - def __replace__(self) -> Self: ... + if sys.version_info >= (3, 14): + def __replace__(self) -> Self: ... + +else: + class AST: + if sys.version_info >= (3, 10): + __match_args__ = () + _attributes: ClassVar[tuple[str, ...]] + _fields: ClassVar[tuple[str, ...]] class mod(AST): ... diff --git a/stdlib/codecs.pyi b/stdlib/codecs.pyi index 15e184fc1038..fa4d4fd4ba92 100644 --- a/stdlib/codecs.pyi +++ b/stdlib/codecs.pyi @@ -1,10 +1,11 @@ +import sys import types from _codecs import * from _typeshed import ReadableBuffer from abc import abstractmethod from collections.abc import Callable, Generator, Iterable from typing import Any, BinaryIO, ClassVar, Final, Literal, Protocol, TextIO, overload, type_check_only -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base __all__ = [ "register", @@ -122,33 +123,64 @@ class _IncrementalDecoder(Protocol): class _BufferedIncrementalDecoder(Protocol): def __call__(self, errors: str = ...) -> BufferedIncrementalDecoder: ... -class CodecInfo(tuple[_Encoder, _Decoder, _StreamReader, _StreamWriter]): - _is_text_encoding: bool - @property - def encode(self) -> _Encoder: ... - @property - def decode(self) -> _Decoder: ... - @property - def streamreader(self) -> _StreamReader: ... - @property - def streamwriter(self) -> _StreamWriter: ... - @property - def incrementalencoder(self) -> _IncrementalEncoder: ... - @property - def incrementaldecoder(self) -> _IncrementalDecoder: ... - name: str - def __new__( - cls, - encode: _Encoder, - decode: _Decoder, - streamreader: _StreamReader | None = None, - streamwriter: _StreamWriter | None = None, - incrementalencoder: _IncrementalEncoder | None = None, - incrementaldecoder: _IncrementalDecoder | None = None, - name: str | None = None, - *, - _is_text_encoding: bool | None = None, - ) -> Self: ... +if sys.version_info >= (3, 12): + class CodecInfo(tuple[_Encoder, _Decoder, _StreamReader, _StreamWriter]): + _is_text_encoding: bool + @property + def encode(self) -> _Encoder: ... + @property + def decode(self) -> _Decoder: ... + @property + def streamreader(self) -> _StreamReader: ... + @property + def streamwriter(self) -> _StreamWriter: ... + @property + def incrementalencoder(self) -> _IncrementalEncoder: ... + @property + def incrementaldecoder(self) -> _IncrementalDecoder: ... + name: str + def __new__( + cls, + encode: _Encoder, + decode: _Decoder, + streamreader: _StreamReader | None = None, + streamwriter: _StreamWriter | None = None, + incrementalencoder: _IncrementalEncoder | None = None, + incrementaldecoder: _IncrementalDecoder | None = None, + name: str | None = None, + *, + _is_text_encoding: bool | None = None, + ) -> Self: ... + +else: + @disjoint_base + class CodecInfo(tuple[_Encoder, _Decoder, _StreamReader, _StreamWriter]): + _is_text_encoding: bool + @property + def encode(self) -> _Encoder: ... + @property + def decode(self) -> _Decoder: ... + @property + def streamreader(self) -> _StreamReader: ... + @property + def streamwriter(self) -> _StreamWriter: ... + @property + def incrementalencoder(self) -> _IncrementalEncoder: ... + @property + def incrementaldecoder(self) -> _IncrementalDecoder: ... + name: str + def __new__( + cls, + encode: _Encoder, + decode: _Decoder, + streamreader: _StreamReader | None = None, + streamwriter: _StreamWriter | None = None, + incrementalencoder: _IncrementalEncoder | None = None, + incrementaldecoder: _IncrementalDecoder | None = None, + name: str | None = None, + *, + _is_text_encoding: bool | None = None, + ) -> Self: ... def getencoder(encoding: str) -> _Encoder: ... def getdecoder(encoding: str) -> _Decoder: ... diff --git a/stdlib/crypt.pyi b/stdlib/crypt.pyi index bd22b5f8daba..f92632196989 100644 --- a/stdlib/crypt.pyi +++ b/stdlib/crypt.pyi @@ -1,5 +1,6 @@ import sys from typing import Final, NamedTuple, type_check_only +from typing_extensions import disjoint_base if sys.platform != "win32": @type_check_only @@ -9,7 +10,12 @@ if sys.platform != "win32": salt_chars: int total_size: int - class _Method(_MethodBase): ... + if sys.version_info >= (3, 12): + class _Method(_MethodBase): ... + else: + @disjoint_base + class _Method(_MethodBase): ... + METHOD_CRYPT: Final[_Method] METHOD_MD5: Final[_Method] METHOD_SHA256: Final[_Method] diff --git a/stdlib/dis.pyi b/stdlib/dis.pyi index 1c32925caf4b..896b50fa9384 100644 --- a/stdlib/dis.pyi +++ b/stdlib/dis.pyi @@ -3,7 +3,7 @@ import types from collections.abc import Callable, Iterator from opcode import * # `dis` re-exports it as a part of public API from typing import IO, Any, Final, NamedTuple -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base __all__ = [ "code_info", @@ -88,39 +88,45 @@ else: starts_line: int | None is_jump_target: bool -class Instruction(_Instruction): - if sys.version_info < (3, 13): +if sys.version_info >= (3, 12): + class Instruction(_Instruction): + if sys.version_info < (3, 13): + def _disassemble(self, lineno_width: int = 3, mark_as_current: bool = False, offset_width: int = 4) -> str: ... + if sys.version_info >= (3, 13): + @property + def oparg(self) -> int: ... + @property + def baseopcode(self) -> int: ... + @property + def baseopname(self) -> str: ... + @property + def cache_offset(self) -> int: ... + @property + def end_offset(self) -> int: ... + @property + def jump_target(self) -> int: ... + @property + def is_jump_target(self) -> bool: ... + if sys.version_info >= (3, 14): + @staticmethod + def make( + opname: str, + arg: int | None, + argval: Any, + argrepr: str, + offset: int, + start_offset: int, + starts_line: bool, + line_number: int | None, + label: int | None = None, + positions: Positions | None = None, + cache_info: list[tuple[str, int, Any]] | None = None, + ) -> Instruction: ... + +else: + @disjoint_base + class Instruction(_Instruction): def _disassemble(self, lineno_width: int = 3, mark_as_current: bool = False, offset_width: int = 4) -> str: ... - if sys.version_info >= (3, 13): - @property - def oparg(self) -> int: ... - @property - def baseopcode(self) -> int: ... - @property - def baseopname(self) -> str: ... - @property - def cache_offset(self) -> int: ... - @property - def end_offset(self) -> int: ... - @property - def jump_target(self) -> int: ... - @property - def is_jump_target(self) -> bool: ... - if sys.version_info >= (3, 14): - @staticmethod - def make( - opname: str, - arg: int | None, - argval: Any, - argrepr: str, - offset: int, - start_offset: int, - starts_line: bool, - line_number: int | None, - label: int | None = None, - positions: Positions | None = None, - cache_info: list[tuple[str, int, Any]] | None = None, - ) -> Instruction: ... class Bytecode: codeobj: types.CodeType diff --git a/stdlib/enum.pyi b/stdlib/enum.pyi index 82054f284949..e11048a61739 100644 --- a/stdlib/enum.pyi +++ b/stdlib/enum.pyi @@ -5,7 +5,7 @@ from _typeshed import SupportsKeysAndGetItem, Unused from builtins import property as _builtins_property from collections.abc import Callable, Iterable, Iterator, Mapping from typing import Any, Final, Generic, Literal, TypeVar, overload -from typing_extensions import Self, TypeAlias +from typing_extensions import Self, TypeAlias, disjoint_base __all__ = ["EnumMeta", "Enum", "IntEnum", "Flag", "IntFlag", "auto", "unique"] @@ -228,16 +228,25 @@ class Enum(metaclass=EnumMeta): if sys.version_info >= (3, 11): class ReprEnum(Enum): ... -if sys.version_info >= (3, 11): - _IntEnumBase = ReprEnum +if sys.version_info >= (3, 12): + class IntEnum(int, ReprEnum): + _value_: int + @_magic_enum_attr + def value(self) -> int: ... + def __new__(cls, value: int) -> Self: ... + else: - _IntEnumBase = Enum + if sys.version_info >= (3, 11): + _IntEnumBase = ReprEnum + else: + _IntEnumBase = Enum -class IntEnum(int, _IntEnumBase): - _value_: int - @_magic_enum_attr - def value(self) -> int: ... - def __new__(cls, value: int) -> Self: ... + @disjoint_base + class IntEnum(int, ReprEnum): + _value_: int + @_magic_enum_attr + def value(self) -> int: ... + def __new__(cls, value: int) -> Self: ... def unique(enumeration: _EnumerationT) -> _EnumerationT: ... @@ -301,8 +310,21 @@ if sys.version_info >= (3, 11): def global_enum_repr(self: Enum) -> str: ... def global_flag_repr(self: Flag) -> str: ... -if sys.version_info >= (3, 11): +if sys.version_info >= (3, 12): + # The body of the class is the same, but the base classes are different. + class IntFlag(int, ReprEnum, Flag, boundary=KEEP): # type: ignore[misc] # complaints about incompatible bases + def __new__(cls, value: int) -> Self: ... + def __or__(self, other: int) -> Self: ... + def __and__(self, other: int) -> Self: ... + def __xor__(self, other: int) -> Self: ... + def __invert__(self) -> Self: ... + __ror__ = __or__ + __rand__ = __and__ + __rxor__ = __xor__ + +elif sys.version_info >= (3, 11): # The body of the class is the same, but the base classes are different. + @disjoint_base class IntFlag(int, ReprEnum, Flag, boundary=KEEP): # type: ignore[misc] # complaints about incompatible bases def __new__(cls, value: int) -> Self: ... def __or__(self, other: int) -> Self: ... @@ -314,6 +336,7 @@ if sys.version_info >= (3, 11): __rxor__ = __xor__ else: + @disjoint_base class IntFlag(int, Flag): # type: ignore[misc] # complaints about incompatible bases def __new__(cls, value: int) -> Self: ... def __or__(self, other: int) -> Self: ... diff --git a/stdlib/inspect.pyi b/stdlib/inspect.pyi index eebf267ed912..15914938de5c 100644 --- a/stdlib/inspect.pyi +++ b/stdlib/inspect.pyi @@ -570,19 +570,6 @@ if sys.version_info >= (3, 11): code_context: list[str] | None index: int | None # type: ignore[assignment] - class Traceback(_Traceback): - positions: dis.Positions | None - def __new__( - cls, - filename: str, - lineno: int, - function: str, - code_context: list[str] | None, - index: int | None, - *, - positions: dis.Positions | None = None, - ) -> Self: ... - class _FrameInfo(NamedTuple): frame: FrameType filename: str @@ -591,19 +578,63 @@ if sys.version_info >= (3, 11): code_context: list[str] | None index: int | None # type: ignore[assignment] - class FrameInfo(_FrameInfo): - positions: dis.Positions | None - def __new__( - cls, - frame: FrameType, - filename: str, - lineno: int, - function: str, - code_context: list[str] | None, - index: int | None, - *, - positions: dis.Positions | None = None, - ) -> Self: ... + if sys.version_info >= (3, 12): + class Traceback(_Traceback): + positions: dis.Positions | None + def __new__( + cls, + filename: str, + lineno: int, + function: str, + code_context: list[str] | None, + index: int | None, + *, + positions: dis.Positions | None = None, + ) -> Self: ... + + class FrameInfo(_FrameInfo): + positions: dis.Positions | None + def __new__( + cls, + frame: FrameType, + filename: str, + lineno: int, + function: str, + code_context: list[str] | None, + index: int | None, + *, + positions: dis.Positions | None = None, + ) -> Self: ... + + else: + @disjoint_base + class Traceback(_Traceback): + positions: dis.Positions | None + def __new__( + cls, + filename: str, + lineno: int, + function: str, + code_context: list[str] | None, + index: int | None, + *, + positions: dis.Positions | None = None, + ) -> Self: ... + + @disjoint_base + class FrameInfo(_FrameInfo): + positions: dis.Positions | None + def __new__( + cls, + frame: FrameType, + filename: str, + lineno: int, + function: str, + code_context: list[str] | None, + index: int | None, + *, + positions: dis.Positions | None = None, + ) -> Self: ... else: class Traceback(NamedTuple): diff --git a/stdlib/logging/config.pyi b/stdlib/logging/config.pyi index 40ee87486144..72412ddc2cea 100644 --- a/stdlib/logging/config.pyi +++ b/stdlib/logging/config.pyi @@ -5,7 +5,7 @@ from configparser import RawConfigParser from re import Pattern from threading import Thread from typing import IO, Any, Final, Literal, SupportsIndex, TypedDict, overload, type_check_only -from typing_extensions import Required, TypeAlias +from typing_extensions import Required, TypeAlias, disjoint_base from . import Filter, Filterer, Formatter, Handler, Logger, _FilterType, _FormatStyle, _Level @@ -100,11 +100,20 @@ class ConvertingList(list[Any], ConvertingMixin): # undocumented def __getitem__(self, key: slice) -> Any: ... def pop(self, idx: SupportsIndex = -1) -> Any: ... -class ConvertingTuple(tuple[Any, ...], ConvertingMixin): # undocumented - @overload - def __getitem__(self, key: SupportsIndex) -> Any: ... - @overload - def __getitem__(self, key: slice) -> Any: ... +if sys.version_info >= (3, 12): + class ConvertingTuple(tuple[Any, ...], ConvertingMixin): # undocumented + @overload + def __getitem__(self, key: SupportsIndex) -> Any: ... + @overload + def __getitem__(self, key: slice) -> Any: ... + +else: + @disjoint_base + class ConvertingTuple(tuple[Any, ...], ConvertingMixin): # undocumented + @overload + def __getitem__(self, key: SupportsIndex) -> Any: ... + @overload + def __getitem__(self, key: slice) -> Any: ... class BaseConfigurator: CONVERT_PATTERN: Pattern[str] diff --git a/stdlib/platform.pyi b/stdlib/platform.pyi index c6125bd3a56f..e5c39401fca1 100644 --- a/stdlib/platform.pyi +++ b/stdlib/platform.pyi @@ -1,6 +1,6 @@ import sys from typing import NamedTuple, type_check_only -from typing_extensions import Self, deprecated +from typing_extensions import Self, deprecated, disjoint_base def libc_ver(executable: str | None = None, lib: str = "", version: str = "", chunksize: int = 16384) -> tuple[str, str]: ... def win32_ver(release: str = "", version: str = "", csd: str = "", ptype: str = "") -> tuple[str, str, str, str]: ... @@ -46,13 +46,23 @@ class _uname_result_base(NamedTuple): # uname_result emulates a 6-field named tuple, but the processor field # is lazily evaluated rather than being passed in to the constructor. -class uname_result(_uname_result_base): - if sys.version_info >= (3, 10): +if sys.version_info >= (3, 12): + class uname_result(_uname_result_base): __match_args__ = ("system", "node", "release", "version", "machine") # pyright: ignore[reportAssignmentType] - def __new__(_cls, system: str, node: str, release: str, version: str, machine: str) -> Self: ... - @property - def processor(self) -> str: ... + def __new__(_cls, system: str, node: str, release: str, version: str, machine: str) -> Self: ... + @property + def processor(self) -> str: ... + +else: + @disjoint_base + class uname_result(_uname_result_base): + if sys.version_info >= (3, 10): + __match_args__ = ("system", "node", "release", "version", "machine") # pyright: ignore[reportAssignmentType] + + def __new__(_cls, system: str, node: str, release: str, version: str, machine: str) -> Self: ... + @property + def processor(self) -> str: ... def uname() -> uname_result: ... def system() -> str: ... diff --git a/stdlib/sre_constants.pyi b/stdlib/sre_constants.pyi index a3921aa0fc3b..9a1da4ac89e7 100644 --- a/stdlib/sre_constants.pyi +++ b/stdlib/sre_constants.pyi @@ -1,15 +1,22 @@ import sys from re import error as error from typing import Final -from typing_extensions import Self +from typing_extensions import Self, disjoint_base MAXGROUPS: Final[int] MAGIC: Final[int] -class _NamedIntConstant(int): - name: str - def __new__(cls, value: int, name: str) -> Self: ... +if sys.version_info >= (3, 12): + class _NamedIntConstant(int): + name: str + def __new__(cls, value: int, name: str) -> Self: ... + +else: + @disjoint_base + class _NamedIntConstant(int): + name: str + def __new__(cls, value: int, name: str) -> Self: ... MAXREPEAT: Final[_NamedIntConstant] OPCODES: list[_NamedIntConstant] diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index f1893ec3194f..fafd6290f957 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -28,7 +28,7 @@ from _ssl import ( from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable from typing import Any, Final, Literal, NamedTuple, TypedDict, overload, type_check_only -from typing_extensions import Never, Self, TypeAlias, deprecated +from typing_extensions import Never, Self, TypeAlias, deprecated, disjoint_base if sys.version_info >= (3, 13): from _ssl import HAS_PSK as HAS_PSK @@ -287,13 +287,44 @@ class _ASN1Object(_ASN1ObjectBase): @classmethod def fromname(cls, name: str) -> Self: ... -class Purpose(_ASN1Object, enum.Enum): - # Normally this class would inherit __new__ from _ASN1Object, but - # because this is an enum, the inherited __new__ is replaced at runtime with - # Enum.__new__. - def __new__(cls, value: object) -> Self: ... - SERVER_AUTH = (129, "serverAuth", "TLS Web Server Authentication", "1.3.6.1.5.5.7.3.2") # pyright: ignore[reportCallIssue] - CLIENT_AUTH = (130, "clientAuth", "TLS Web Client Authentication", "1.3.6.1.5.5.7.3.1") # pyright: ignore[reportCallIssue] +if sys.version_info >= (3, 12): + class Purpose(_ASN1Object, enum.Enum): + # Normally this class would inherit __new__ from _ASN1Object, but + # because this is an enum, the inherited __new__ is replaced at runtime with + # Enum.__new__. + def __new__(cls, value: object) -> Self: ... + SERVER_AUTH = ( + 129, + "serverAuth", + "TLS Web Server Authentication", + "1.3.6.1.5.5.7.3.2", + ) # pyright: ignore[reportCallIssue] + CLIENT_AUTH = ( + 130, + "clientAuth", + "TLS Web Client Authentication", + "1.3.6.1.5.5.7.3.1", + ) # pyright: ignore[reportCallIssue] + +else: + @disjoint_base + class Purpose(_ASN1Object, enum.Enum): + # Normally this class would inherit __new__ from _ASN1Object, but + # because this is an enum, the inherited __new__ is replaced at runtime with + # Enum.__new__. + def __new__(cls, value: object) -> Self: ... + SERVER_AUTH = ( + 129, + "serverAuth", + "TLS Web Server Authentication", + "1.3.6.1.5.5.7.3.2", + ) # pyright: ignore[reportCallIssue] + CLIENT_AUTH = ( + 130, + "clientAuth", + "TLS Web Client Authentication", + "1.3.6.1.5.5.7.3.1", + ) # pyright: ignore[reportCallIssue] class SSLSocket(socket.socket): context: SSLContext diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index 76b2ddcf17df..45cbf1a5dd2b 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -6,7 +6,7 @@ from tkinter.constants import * from tkinter.font import _FontDescription from types import GenericAlias, TracebackType from typing import Any, ClassVar, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, type_check_only -from typing_extensions import TypeAlias, TypeVarTuple, Unpack, deprecated +from typing_extensions import TypeAlias, TypeVarTuple, Unpack, deprecated, disjoint_base if sys.version_info >= (3, 11): from enum import StrEnum @@ -198,7 +198,11 @@ if sys.version_info >= (3, 11): releaselevel: str serial: int - class _VersionInfoType(_VersionInfoTypeBase): ... + if sys.version_info >= (3, 12): + class _VersionInfoType(_VersionInfoTypeBase): ... + else: + @disjoint_base + class _VersionInfoType(_VersionInfoTypeBase): ... if sys.version_info >= (3, 11): class EventType(StrEnum): diff --git a/stdlib/tokenize.pyi b/stdlib/tokenize.pyi index dabb64b8b96e..00a24b4eea07 100644 --- a/stdlib/tokenize.pyi +++ b/stdlib/tokenize.pyi @@ -4,7 +4,7 @@ from collections.abc import Callable, Generator, Iterable, Sequence from re import Pattern from token import * from typing import Any, Final, NamedTuple, TextIO, type_check_only -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base if sys.version_info < (3, 12): # Avoid double assignment to Final name by imports, which pyright objects to. @@ -115,9 +115,16 @@ class _TokenInfo(NamedTuple): end: _Position line: str -class TokenInfo(_TokenInfo): - @property - def exact_type(self) -> int: ... +if sys.version_info >= (3, 12): + class TokenInfo(_TokenInfo): + @property + def exact_type(self) -> int: ... + +else: + @disjoint_base + class TokenInfo(_TokenInfo): + @property + def exact_type(self) -> int: ... # Backwards compatible tokens can be sequences of a shorter length too _Token: TypeAlias = TokenInfo | Sequence[int | str | _Position] diff --git a/stdlib/turtle.pyi b/stdlib/turtle.pyi index e41476b73b8c..0b93429904c5 100644 --- a/stdlib/turtle.pyi +++ b/stdlib/turtle.pyi @@ -4,7 +4,7 @@ from collections.abc import Callable, Generator, Sequence from contextlib import contextmanager from tkinter import Canvas, Frame, Misc, PhotoImage, Scrollbar from typing import Any, ClassVar, Literal, TypedDict, overload, type_check_only -from typing_extensions import Self, TypeAlias, deprecated +from typing_extensions import Self, TypeAlias, deprecated, disjoint_base __all__ = [ "ScrolledCanvas", @@ -163,18 +163,34 @@ class _PenState(TypedDict): _Speed: TypeAlias = str | float _PolygonCoords: TypeAlias = Sequence[tuple[float, float]] -class Vec2D(tuple[float, float]): - def __new__(cls, x: float, y: float) -> Self: ... - def __add__(self, other: tuple[float, float]) -> Vec2D: ... # type: ignore[override] - @overload # type: ignore[override] - def __mul__(self, other: Vec2D) -> float: ... - @overload - def __mul__(self, other: float) -> Vec2D: ... - def __rmul__(self, other: float) -> Vec2D: ... # type: ignore[override] - def __sub__(self, other: tuple[float, float]) -> Vec2D: ... - def __neg__(self) -> Vec2D: ... - def __abs__(self) -> float: ... - def rotate(self, angle: float) -> Vec2D: ... +if sys.version_info >= (3, 12): + class Vec2D(tuple[float, float]): + def __new__(cls, x: float, y: float) -> Self: ... + def __add__(self, other: tuple[float, float]) -> Vec2D: ... # type: ignore[override] + @overload # type: ignore[override] + def __mul__(self, other: Vec2D) -> float: ... + @overload + def __mul__(self, other: float) -> Vec2D: ... + def __rmul__(self, other: float) -> Vec2D: ... # type: ignore[override] + def __sub__(self, other: tuple[float, float]) -> Vec2D: ... + def __neg__(self) -> Vec2D: ... + def __abs__(self) -> float: ... + def rotate(self, angle: float) -> Vec2D: ... + +else: + @disjoint_base + class Vec2D(tuple[float, float]): + def __new__(cls, x: float, y: float) -> Self: ... + def __add__(self, other: tuple[float, float]) -> Vec2D: ... # type: ignore[override] + @overload # type: ignore[override] + def __mul__(self, other: Vec2D) -> float: ... + @overload + def __mul__(self, other: float) -> Vec2D: ... + def __rmul__(self, other: float) -> Vec2D: ... # type: ignore[override] + def __sub__(self, other: tuple[float, float]) -> Vec2D: ... + def __neg__(self) -> Vec2D: ... + def __abs__(self) -> float: ... + def rotate(self, angle: float) -> Vec2D: ... # Does not actually inherit from Canvas, but dynamically gets all methods of Canvas class ScrolledCanvas(Canvas, Frame): # type: ignore[misc] diff --git a/stdlib/types.pyi b/stdlib/types.pyi index a6be9b14b6be..a8faa3f77320 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -331,20 +331,32 @@ class MappingProxyType(Mapping[_KT, _VT_co]): def __or__(self, value: Mapping[_T1, _T2], /) -> dict[_KT | _T1, _VT_co | _T2]: ... def __ror__(self, value: Mapping[_T1, _T2], /) -> dict[_KT | _T1, _VT_co | _T2]: ... -@disjoint_base -class SimpleNamespace: - __hash__: ClassVar[None] # type: ignore[assignment] - if sys.version_info >= (3, 13): - def __init__(self, mapping_or_iterable: Mapping[str, Any] | Iterable[tuple[str, Any]] = (), /, **kwargs: Any) -> None: ... - else: - def __init__(self, **kwargs: Any) -> None: ... +if sys.version_info >= (3, 12): + @disjoint_base + class SimpleNamespace: + __hash__: ClassVar[None] # type: ignore[assignment] + if sys.version_info >= (3, 13): + def __init__( + self, mapping_or_iterable: Mapping[str, Any] | Iterable[tuple[str, Any]] = (), /, **kwargs: Any + ) -> None: ... + else: + def __init__(self, **kwargs: Any) -> None: ... - def __eq__(self, value: object, /) -> bool: ... - def __getattribute__(self, name: str, /) -> Any: ... - def __setattr__(self, name: str, value: Any, /) -> None: ... - def __delattr__(self, name: str, /) -> None: ... - if sys.version_info >= (3, 13): - def __replace__(self, **kwargs: Any) -> Self: ... + def __eq__(self, value: object, /) -> bool: ... + def __getattribute__(self, name: str, /) -> Any: ... + def __setattr__(self, name: str, value: Any, /) -> None: ... + def __delattr__(self, name: str, /) -> None: ... + if sys.version_info >= (3, 13): + def __replace__(self, **kwargs: Any) -> Self: ... + +else: + class SimpleNamespace: + __hash__: ClassVar[None] # type: ignore[assignment] + def __init__(self, **kwargs: Any) -> None: ... + def __eq__(self, value: object, /) -> bool: ... + def __getattribute__(self, name: str, /) -> Any: ... + def __setattr__(self, name: str, value: Any, /) -> None: ... + def __delattr__(self, name: str, /) -> None: ... @disjoint_base class ModuleType: diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index 6b0941a91719..d219d90e8a70 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -4,7 +4,7 @@ from collections.abc import Awaitable, Callable, Coroutine, Iterable, Mapping, S from contextlib import _GeneratorContextManager from types import TracebackType from typing import Any, ClassVar, Final, Generic, Literal, TypeVar, overload, type_check_only -from typing_extensions import ParamSpec, Self, TypeAlias +from typing_extensions import ParamSpec, Self, TypeAlias, disjoint_base _T = TypeVar("_T") _TT = TypeVar("_TT", bound=type[Any]) @@ -68,29 +68,66 @@ _ArgsKwargs: TypeAlias = tuple[tuple[Any, ...], Mapping[str, Any]] _NameArgsKwargs: TypeAlias = tuple[str, tuple[Any, ...], Mapping[str, Any]] _CallValue: TypeAlias = str | tuple[Any, ...] | Mapping[str, Any] | _ArgsKwargs | _NameArgsKwargs -class _Call(tuple[Any, ...]): - def __new__( - cls, value: _CallValue = (), name: str | None = "", parent: _Call | None = None, two: bool = False, from_kall: bool = True - ) -> Self: ... - def __init__( - self, - value: _CallValue = (), - name: str | None = None, - parent: _Call | None = None, - two: bool = False, - from_kall: bool = True, - ) -> None: ... - __hash__: ClassVar[None] # type: ignore[assignment] - def __eq__(self, other: object) -> bool: ... - def __ne__(self, value: object, /) -> bool: ... - def __call__(self, *args: Any, **kwargs: Any) -> _Call: ... - def __getattr__(self, attr: str) -> Any: ... - def __getattribute__(self, attr: str) -> Any: ... - @property - def args(self) -> tuple[Any, ...]: ... - @property - def kwargs(self) -> Mapping[str, Any]: ... - def call_list(self) -> Any: ... +if sys.version_info >= (3, 12): + class _Call(tuple[Any, ...]): + def __new__( + cls, + value: _CallValue = (), + name: str | None = "", + parent: _Call | None = None, + two: bool = False, + from_kall: bool = True, + ) -> Self: ... + def __init__( + self, + value: _CallValue = (), + name: str | None = None, + parent: _Call | None = None, + two: bool = False, + from_kall: bool = True, + ) -> None: ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __eq__(self, other: object) -> bool: ... + def __ne__(self, value: object, /) -> bool: ... + def __call__(self, *args: Any, **kwargs: Any) -> _Call: ... + def __getattr__(self, attr: str) -> Any: ... + def __getattribute__(self, attr: str) -> Any: ... + @property + def args(self) -> tuple[Any, ...]: ... + @property + def kwargs(self) -> Mapping[str, Any]: ... + def call_list(self) -> Any: ... + +else: + @disjoint_base + class _Call(tuple[Any, ...]): + def __new__( + cls, + value: _CallValue = (), + name: str | None = "", + parent: _Call | None = None, + two: bool = False, + from_kall: bool = True, + ) -> Self: ... + def __init__( + self, + value: _CallValue = (), + name: str | None = None, + parent: _Call | None = None, + two: bool = False, + from_kall: bool = True, + ) -> None: ... + __hash__: ClassVar[None] # type: ignore[assignment] + def __eq__(self, other: object) -> bool: ... + def __ne__(self, value: object, /) -> bool: ... + def __call__(self, *args: Any, **kwargs: Any) -> _Call: ... + def __getattr__(self, attr: str) -> Any: ... + def __getattribute__(self, attr: str) -> Any: ... + @property + def args(self) -> tuple[Any, ...]: ... + @property + def kwargs(self) -> Mapping[str, Any]: ... + def call_list(self) -> Any: ... call: _Call From b978f2f3c97438558c4e5e051b02b23a875dd760 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Wed, 20 Aug 2025 15:38:20 -0700 Subject: [PATCH 04/21] . --- stdlib/enum.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/enum.pyi b/stdlib/enum.pyi index e11048a61739..4ac860f5e611 100644 --- a/stdlib/enum.pyi +++ b/stdlib/enum.pyi @@ -242,7 +242,7 @@ else: _IntEnumBase = Enum @disjoint_base - class IntEnum(int, ReprEnum): + class IntEnum(int, _IntEnumBase): _value_: int @_magic_enum_attr def value(self) -> int: ... From 45eabe594160c9e4c7c6e840ec7bed3acf36ce62 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 02:33:07 +0000 Subject: [PATCH 05/21] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/_interpreters.pyi | 4 +--- stdlib/tkinter/__init__.pyi | 4 +--- stdlib/xml/dom/expatbuilder.pyi | 4 +--- stdlib/xml/dom/xmlbuilder.pyi | 3 +-- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/stdlib/_interpreters.pyi b/stdlib/_interpreters.pyi index ec241081635a..8e097efad618 100644 --- a/stdlib/_interpreters.pyi +++ b/stdlib/_interpreters.pyi @@ -1,9 +1,7 @@ import types from collections.abc import Callable -from typing import Any, Final, Literal, SupportsIndex, TypeVar -from typing_extensions import TypeAlias, disjoint_base from typing import Any, Final, Literal, SupportsIndex, TypeVar, overload -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base _R = TypeVar("_R") diff --git a/stdlib/tkinter/__init__.pyi b/stdlib/tkinter/__init__.pyi index f3bbefa6bad0..42675c0eb67c 100644 --- a/stdlib/tkinter/__init__.pyi +++ b/stdlib/tkinter/__init__.pyi @@ -5,10 +5,8 @@ from collections.abc import Callable, Iterable, Mapping, Sequence from tkinter.constants import * from tkinter.font import _FontDescription from types import GenericAlias, TracebackType -from typing import Any, ClassVar, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, type_check_only -from typing_extensions import TypeAlias, TypeVarTuple, Unpack, deprecated, disjoint_base from typing import Any, ClassVar, Final, Generic, Literal, NamedTuple, Protocol, TypedDict, TypeVar, overload, type_check_only -from typing_extensions import TypeAlias, TypeVarTuple, Unpack, deprecated +from typing_extensions import TypeAlias, TypeVarTuple, Unpack, deprecated, disjoint_base if sys.version_info >= (3, 11): from enum import StrEnum diff --git a/stdlib/xml/dom/expatbuilder.pyi b/stdlib/xml/dom/expatbuilder.pyi index 217131948779..297c55cf3c5d 100644 --- a/stdlib/xml/dom/expatbuilder.pyi +++ b/stdlib/xml/dom/expatbuilder.pyi @@ -1,8 +1,6 @@ from _typeshed import ReadableBuffer, SupportsRead -from typing import Any, NoReturn -from typing_extensions import TypeAlias, disjoint_base from typing import Any, Final, NoReturn -from typing_extensions import TypeAlias +from typing_extensions import TypeAlias, disjoint_base from xml.dom.minidom import Document, DocumentFragment, DOMImplementation, Element, Node, TypeInfo from xml.dom.xmlbuilder import DOMBuilderFilter, Options from xml.parsers.expat import XMLParserType diff --git a/stdlib/xml/dom/xmlbuilder.pyi b/stdlib/xml/dom/xmlbuilder.pyi index ca21653084f5..e5e6b3f13863 100644 --- a/stdlib/xml/dom/xmlbuilder.pyi +++ b/stdlib/xml/dom/xmlbuilder.pyi @@ -1,7 +1,6 @@ from _typeshed import SupportsRead -from typing import Any, Literal, NoReturn -from typing_extensions import disjoint_base from typing import Any, Final, Literal, NoReturn +from typing_extensions import disjoint_base from xml.dom.minidom import Document, Node, _DOMErrorHandler __all__ = ["DOMBuilder", "DOMEntityResolver", "DOMInputSource"] From 1cedf1bcb6536f9386014dfe438893cfddb7981a Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 19:35:35 -0700 Subject: [PATCH 06/21] python -m stubdefaulter --only disjoint-base-with-slots --stdlib ../typeshed/stdlib/ --fix --- stdlib/_threading_local.pyi | 4 +--- stdlib/asyncio/events.pyi | 4 +--- stdlib/asyncio/transports.pyi | 3 --- stdlib/asyncio/trsock.pyi | 3 +-- stdlib/dataclasses.pyi | 4 +--- stdlib/fractions.pyi | 3 +-- stdlib/hmac.pyi | 4 ++-- stdlib/inspect.pyi | 3 --- stdlib/ipaddress.pyi | 4 +--- stdlib/multiprocessing/managers.pyi | 3 +-- stdlib/pathlib/__init__.pyi | 3 +-- stdlib/pickletools.pyi | 5 +---- stdlib/socket.pyi | 3 +-- stdlib/statistics.pyi | 4 ++-- stdlib/traceback.pyi | 3 +-- stdlib/tracemalloc.pyi | 7 +------ stdlib/uuid.pyi | 3 +-- stdlib/weakref.pyi | 2 -- stdlib/xml/dom/expatbuilder.pyi | 5 +---- stdlib/xml/dom/minidom.pyi | 12 +----------- stdlib/xml/dom/xmlbuilder.pyi | 3 --- stdlib/zipfile/__init__.pyi | 3 +-- 22 files changed, 20 insertions(+), 68 deletions(-) diff --git a/stdlib/_threading_local.pyi b/stdlib/_threading_local.pyi index b4fc01324bdf..5f6acaf840aa 100644 --- a/stdlib/_threading_local.pyi +++ b/stdlib/_threading_local.pyi @@ -1,12 +1,11 @@ from threading import RLock from typing import Any -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias from weakref import ReferenceType __all__ = ["local"] _LocalDict: TypeAlias = dict[Any, Any] -@disjoint_base class _localimpl: __slots__ = ("key", "dicts", "localargs", "locallock", "__weakref__") key: str @@ -17,7 +16,6 @@ class _localimpl: def get_dict(self) -> _LocalDict: ... def create_dict(self) -> _LocalDict: ... -@disjoint_base class local: __slots__ = ("_local__impl", "__dict__") def __new__(cls, /, *args: Any, **kw: Any) -> Self: ... diff --git a/stdlib/asyncio/events.pyi b/stdlib/asyncio/events.pyi index bc364a15a32e..5a6b0f31d369 100644 --- a/stdlib/asyncio/events.pyi +++ b/stdlib/asyncio/events.pyi @@ -13,7 +13,7 @@ from concurrent.futures import Executor from contextvars import Context from socket import AddressFamily, SocketKind, _Address, _RetAddress, socket from typing import IO, Any, Literal, Protocol, TypeVar, overload, type_check_only -from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack, deprecated, disjoint_base +from typing_extensions import Self, TypeAlias, TypeVarTuple, Unpack, deprecated from . import _AwaitableLike, _CoroutineLike from .base_events import Server @@ -72,7 +72,6 @@ _SSLContext: TypeAlias = bool | None | ssl.SSLContext class _TaskFactory(Protocol): def __call__(self, loop: AbstractEventLoop, factory: _CoroutineLike[_T], /) -> Future[_T]: ... -@disjoint_base class Handle: __slots__ = ("_callback", "_args", "_cancelled", "_loop", "_source_traceback", "_repr", "__weakref__", "_context") _cancelled: bool @@ -86,7 +85,6 @@ class Handle: if sys.version_info >= (3, 12): def get_context(self) -> Context: ... -@disjoint_base class TimerHandle(Handle): __slots__ = ["_scheduled", "_when"] def __init__( diff --git a/stdlib/asyncio/transports.pyi b/stdlib/asyncio/transports.pyi index 3e3821e640e5..cc870d5e0b9a 100644 --- a/stdlib/asyncio/transports.pyi +++ b/stdlib/asyncio/transports.pyi @@ -3,12 +3,10 @@ from asyncio.protocols import BaseProtocol from collections.abc import Iterable, Mapping from socket import _Address from typing import Any -from typing_extensions import disjoint_base # Keep asyncio.__all__ updated with any changes to __all__ here __all__ = ("BaseTransport", "ReadTransport", "WriteTransport", "Transport", "DatagramTransport", "SubprocessTransport") -@disjoint_base class BaseTransport: __slots__ = ("_extra",) def __init__(self, extra: Mapping[str, Any] | None = None) -> None: ... @@ -54,7 +52,6 @@ class SubprocessTransport(BaseTransport): def terminate(self) -> None: ... def kill(self) -> None: ... -@disjoint_base class _FlowControlMixin(Transport): __slots__ = ("_loop", "_protocol_paused", "_high_water", "_low_water") def __init__(self, extra: Mapping[str, Any] | None = None, loop: AbstractEventLoop | None = None) -> None: ... diff --git a/stdlib/asyncio/trsock.pyi b/stdlib/asyncio/trsock.pyi index b3b51443f1f2..8f4f8f9ccb30 100644 --- a/stdlib/asyncio/trsock.pyi +++ b/stdlib/asyncio/trsock.pyi @@ -5,7 +5,7 @@ from builtins import type as Type # alias to avoid name clashes with property n from collections.abc import Iterable from types import TracebackType from typing import Any, BinaryIO, NoReturn, overload -from typing_extensions import TypeAlias, deprecated, disjoint_base +from typing_extensions import TypeAlias, deprecated # These are based in socket, maybe move them out into _typeshed.pyi or such _Address: TypeAlias = socket._Address @@ -13,7 +13,6 @@ _RetAddress: TypeAlias = Any _WriteBuffer: TypeAlias = bytearray | memoryview _CMSG: TypeAlias = tuple[int, int, bytes] -@disjoint_base class TransportSocket: __slots__ = ("_sock",) def __init__(self, sock: socket.socket) -> None: ... diff --git a/stdlib/dataclasses.pyi b/stdlib/dataclasses.pyi index 54ae8228131f..3a1c8cb5d62d 100644 --- a/stdlib/dataclasses.pyi +++ b/stdlib/dataclasses.pyi @@ -6,7 +6,7 @@ from builtins import type as Type # alias to avoid name clashes with fields nam from collections.abc import Callable, Iterable, Mapping from types import GenericAlias from typing import Any, Final, Generic, Literal, Protocol, TypeVar, overload, type_check_only -from typing_extensions import Never, TypeIs, disjoint_base +from typing_extensions import Never, TypeIs _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) @@ -169,7 +169,6 @@ else: class _DefaultFactory(Protocol[_T_co]): def __call__(self) -> _T_co: ... -@disjoint_base class Field(Generic[_T]): if sys.version_info >= (3, 14): __slots__ = ( @@ -386,7 +385,6 @@ def is_dataclass(obj: object) -> TypeIs[DataclassInstance | type[DataclassInstan class FrozenInstanceError(AttributeError): ... -@disjoint_base class InitVar(Generic[_T]): __slots__ = ("type",) type: Type[_T] diff --git a/stdlib/fractions.pyi b/stdlib/fractions.pyi index 33c7cb1dc477..ef4066aa65b5 100644 --- a/stdlib/fractions.pyi +++ b/stdlib/fractions.pyi @@ -3,7 +3,7 @@ from collections.abc import Callable from decimal import Decimal from numbers import Rational, Real from typing import Any, Literal, Protocol, SupportsIndex, overload, type_check_only -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias _ComparableNum: TypeAlias = int | float | Decimal | Real @@ -13,7 +13,6 @@ __all__ = ["Fraction"] class _ConvertibleToIntegerRatio(Protocol): def as_integer_ratio(self) -> tuple[int | Rational, int | Rational]: ... -@disjoint_base class Fraction(Rational): __slots__ = ("_numerator", "_denominator") @overload diff --git a/stdlib/hmac.pyi b/stdlib/hmac.pyi index 6b8ad7e949d3..070c59b1c166 100644 --- a/stdlib/hmac.pyi +++ b/stdlib/hmac.pyi @@ -3,7 +3,7 @@ from _typeshed import ReadableBuffer, SizedBuffer from collections.abc import Callable from types import ModuleType from typing import overload -from typing_extensions import TypeAlias, disjoint_base +from typing_extensions import TypeAlias _DigestMod: TypeAlias = str | Callable[[], _HashObject] | ModuleType @@ -18,7 +18,7 @@ digest_size: None def new(key: bytes | bytearray, msg: ReadableBuffer | None, digestmod: _DigestMod) -> HMAC: ... @overload def new(key: bytes | bytearray, *, digestmod: _DigestMod) -> HMAC: ... -@disjoint_base + class HMAC: __slots__ = ("_hmac", "_inner", "_outer", "block_size", "digest_size") digest_size: int diff --git a/stdlib/inspect.pyi b/stdlib/inspect.pyi index 28c93d9ee724..55ae61617af7 100644 --- a/stdlib/inspect.pyi +++ b/stdlib/inspect.pyi @@ -335,7 +335,6 @@ else: class _void: ... class _empty: ... -@disjoint_base class Signature: __slots__ = ("_return_annotation", "_parameters") def __init__( @@ -417,7 +416,6 @@ if sys.version_info >= (3, 12): ) -> Literal["AGEN_CREATED", "AGEN_RUNNING", "AGEN_SUSPENDED", "AGEN_CLOSED"]: ... def getasyncgenlocals(agen: AsyncGeneratorType[Any, Any]) -> dict[str, Any]: ... -@disjoint_base class Parameter: __slots__ = ("_name", "_kind", "_default", "_annotation") def __init__(self, name: str, kind: _ParameterKind, *, default: Any = ..., annotation: Any = ...) -> None: ... @@ -450,7 +448,6 @@ class Parameter: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... -@disjoint_base class BoundArguments: __slots__ = ("arguments", "_signature", "__weakref__") arguments: OrderedDict[str, Any] diff --git a/stdlib/ipaddress.pyi b/stdlib/ipaddress.pyi index c584a4d098a0..d09804cb9342 100644 --- a/stdlib/ipaddress.pyi +++ b/stdlib/ipaddress.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Iterable, Iterator from typing import Any, Final, Generic, Literal, TypeVar, overload -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias # Undocumented length constants IPV4LENGTH: Final = 32 @@ -117,7 +117,6 @@ class _BaseV4: @property def max_prefixlen(self) -> Literal[32]: ... -@disjoint_base class IPv4Address(_BaseV4, _BaseAddress): __slots__ = ("_ip", "__weakref__") def __init__(self, address: object) -> None: ... @@ -171,7 +170,6 @@ class _BaseV6: @property def max_prefixlen(self) -> Literal[128]: ... -@disjoint_base class IPv6Address(_BaseV6, _BaseAddress): __slots__ = ("_ip", "_scope_id", "__weakref__") def __init__(self, address: object) -> None: ... diff --git a/stdlib/multiprocessing/managers.pyi b/stdlib/multiprocessing/managers.pyi index 30f5c3120112..5efe69a97377 100644 --- a/stdlib/multiprocessing/managers.pyi +++ b/stdlib/multiprocessing/managers.pyi @@ -15,7 +15,7 @@ from collections.abc import ( ) from types import GenericAlias, TracebackType from typing import Any, AnyStr, ClassVar, Generic, SupportsIndex, TypeVar, overload -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias from . import pool from .connection import Connection, _Address @@ -37,7 +37,6 @@ class Namespace: _Namespace: TypeAlias = Namespace -@disjoint_base class Token: __slots__ = ("typeid", "address", "id") typeid: str | bytes | None diff --git a/stdlib/pathlib/__init__.pyi b/stdlib/pathlib/__init__.pyi index ac910a96d4de..fa5143f20292 100644 --- a/stdlib/pathlib/__init__.pyi +++ b/stdlib/pathlib/__init__.pyi @@ -16,7 +16,7 @@ from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWra from os import PathLike, stat_result from types import GenericAlias, TracebackType from typing import IO, Any, BinaryIO, ClassVar, Literal, TypeVar, overload -from typing_extensions import Never, Self, deprecated, disjoint_base +from typing_extensions import Never, Self, deprecated _PathT = TypeVar("_PathT", bound=PurePath) @@ -28,7 +28,6 @@ if sys.version_info >= (3, 14): if sys.version_info >= (3, 13): __all__ += ["UnsupportedOperation"] -@disjoint_base class PurePath(PathLike[str]): if sys.version_info >= (3, 13): __slots__ = ( diff --git a/stdlib/pickletools.pyi b/stdlib/pickletools.pyi index 1dfda587549a..8bbfaba31b67 100644 --- a/stdlib/pickletools.pyi +++ b/stdlib/pickletools.pyi @@ -1,7 +1,7 @@ import sys from collections.abc import Callable, Iterator, MutableMapping from typing import IO, Any, Final -from typing_extensions import TypeAlias, disjoint_base +from typing_extensions import TypeAlias __all__ = ["dis", "genops", "optimize"] @@ -14,7 +14,6 @@ TAKEN_FROM_ARGUMENT4: Final = -3 TAKEN_FROM_ARGUMENT4U: Final = -4 TAKEN_FROM_ARGUMENT8U: Final = -5 -@disjoint_base class ArgumentDescriptor: __slots__ = ("name", "n", "reader", "doc") name: str @@ -119,7 +118,6 @@ def read_long4(f: IO[bytes]) -> int: ... long4: ArgumentDescriptor -@disjoint_base class StackObject: __slots__ = ("name", "obtype", "doc") name: str @@ -146,7 +144,6 @@ anyobject: StackObject markobject: StackObject stackslice: StackObject -@disjoint_base class OpcodeInfo: __slots__ = ("name", "code", "arg", "stack_before", "stack_after", "proto", "doc") name: str diff --git a/stdlib/socket.pyi b/stdlib/socket.pyi index b1130dcc6348..b10b3560b91f 100644 --- a/stdlib/socket.pyi +++ b/stdlib/socket.pyi @@ -137,7 +137,7 @@ from collections.abc import Iterable from enum import IntEnum, IntFlag from io import BufferedReader, BufferedRWPair, BufferedWriter, IOBase, RawIOBase, TextIOWrapper from typing import Any, Final, Literal, Protocol, SupportsIndex, overload, type_check_only -from typing_extensions import Self, disjoint_base +from typing_extensions import Self __all__ = [ "fromfd", @@ -1299,7 +1299,6 @@ class _SendableFile(Protocol): # def mode(self) -> str: ... # def fileno(self) -> int: ... -@disjoint_base class socket(_socket.socket): __slots__ = ["__weakref__", "_io_refs", "_closed"] def __init__( diff --git a/stdlib/statistics.pyi b/stdlib/statistics.pyi index b21c23e83529..ba9e5f1b6b71 100644 --- a/stdlib/statistics.pyi +++ b/stdlib/statistics.pyi @@ -4,7 +4,7 @@ from collections.abc import Callable, Hashable, Iterable, Sequence from decimal import Decimal from fractions import Fraction from typing import Literal, NamedTuple, SupportsFloat, SupportsIndex, TypeVar -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias __all__ = [ "StatisticsError", @@ -77,7 +77,7 @@ def quantiles( ) -> list[_NumberT]: ... def stdev(data: Iterable[_NumberT], xbar: _NumberT | None = None) -> _NumberT: ... def variance(data: Iterable[_NumberT], xbar: _NumberT | None = None) -> _NumberT: ... -@disjoint_base + class NormalDist: __slots__ = {"_mu": "Arithmetic mean of a normal distribution", "_sigma": "Standard deviation of a normal distribution"} def __init__(self, mu: float = 0.0, sigma: float = 1.0) -> None: ... diff --git a/stdlib/traceback.pyi b/stdlib/traceback.pyi index cf78f412235e..d587295cd1cf 100644 --- a/stdlib/traceback.pyi +++ b/stdlib/traceback.pyi @@ -3,7 +3,7 @@ from _typeshed import SupportsWrite, Unused from collections.abc import Generator, Iterable, Iterator, Mapping from types import FrameType, TracebackType from typing import Any, ClassVar, Literal, overload -from typing_extensions import Self, TypeAlias, deprecated, disjoint_base +from typing_extensions import Self, TypeAlias, deprecated __all__ = [ "extract_stack", @@ -244,7 +244,6 @@ class TracebackException: if sys.version_info >= (3, 11): def print(self, *, file: SupportsWrite[str] | None = None, chain: bool = True) -> None: ... -@disjoint_base class FrameSummary: if sys.version_info >= (3, 13): __slots__ = ( diff --git a/stdlib/tracemalloc.pyi b/stdlib/tracemalloc.pyi index 076f4404c9c1..31d8f7445639 100644 --- a/stdlib/tracemalloc.pyi +++ b/stdlib/tracemalloc.pyi @@ -2,7 +2,7 @@ import sys from _tracemalloc import * from collections.abc import Sequence from typing import Any, SupportsIndex, overload -from typing_extensions import TypeAlias, disjoint_base +from typing_extensions import TypeAlias def get_object_traceback(obj: object) -> Traceback | None: ... def take_snapshot() -> Snapshot: ... @@ -31,7 +31,6 @@ class Filter(BaseFilter): domain: int | None = None, ) -> None: ... -@disjoint_base class Statistic: __slots__ = ("traceback", "size", "count") count: int @@ -41,7 +40,6 @@ class Statistic: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... -@disjoint_base class StatisticDiff: __slots__ = ("traceback", "size", "size_diff", "count", "count_diff") count: int @@ -55,7 +53,6 @@ class StatisticDiff: _FrameTuple: TypeAlias = tuple[str, int] -@disjoint_base class Frame: __slots__ = ("_frame",) @property @@ -77,7 +74,6 @@ class Frame: _TraceTuple: TypeAlias = tuple[int, int, Sequence[_FrameTuple], int | None] | tuple[int, int, Sequence[_FrameTuple]] -@disjoint_base class Trace: __slots__ = ("_trace",) @property @@ -90,7 +86,6 @@ class Trace: def __eq__(self, other: object) -> bool: ... def __hash__(self) -> int: ... -@disjoint_base class Traceback(Sequence[Frame]): __slots__ = ("_frames", "_total_nframe") @property diff --git a/stdlib/uuid.pyi b/stdlib/uuid.pyi index fe173ecb90a5..303fb10eaf53 100644 --- a/stdlib/uuid.pyi +++ b/stdlib/uuid.pyi @@ -2,7 +2,7 @@ import builtins import sys from enum import Enum from typing import Final -from typing_extensions import LiteralString, TypeAlias, disjoint_base +from typing_extensions import LiteralString, TypeAlias _FieldsType: TypeAlias = tuple[int, int, int, int, int, int] @@ -11,7 +11,6 @@ class SafeUUID(Enum): unsafe = -1 unknown = None -@disjoint_base class UUID: __slots__ = ("int", "is_safe", "__weakref__") def __init__( diff --git a/stdlib/weakref.pyi b/stdlib/weakref.pyi index ab6f4b4d6f09..76ab86b957a1 100644 --- a/stdlib/weakref.pyi +++ b/stdlib/weakref.pyi @@ -65,7 +65,6 @@ ref = ReferenceType # everything below here is implemented in weakref.py -@disjoint_base class WeakMethod(ref[_CallableT]): __slots__ = ("_func_ref", "_meth_type", "_alive", "__weakref__") def __new__(cls, meth: _CallableT, callback: Callable[[Self], Any] | None = None) -> Self: ... @@ -132,7 +131,6 @@ class WeakValueDictionary(MutableMapping[_KT, _VT]): @overload def __ior__(self, other: Iterable[tuple[_KT, _VT]]) -> Self: ... -@disjoint_base class KeyedRef(ref[_T], Generic[_KT, _T]): __slots__ = ("key",) key: _KT diff --git a/stdlib/xml/dom/expatbuilder.pyi b/stdlib/xml/dom/expatbuilder.pyi index 297c55cf3c5d..2b9ac8876970 100644 --- a/stdlib/xml/dom/expatbuilder.pyi +++ b/stdlib/xml/dom/expatbuilder.pyi @@ -1,6 +1,6 @@ from _typeshed import ReadableBuffer, SupportsRead from typing import Any, Final, NoReturn -from typing_extensions import TypeAlias, disjoint_base +from typing_extensions import TypeAlias from xml.dom.minidom import Document, DocumentFragment, DOMImplementation, Element, Node, TypeInfo from xml.dom.xmlbuilder import DOMBuilderFilter, Options from xml.parsers.expat import XMLParserType @@ -16,7 +16,6 @@ FILTER_SKIP: Final = DOMBuilderFilter.FILTER_SKIP FILTER_INTERRUPT: Final = DOMBuilderFilter.FILTER_INTERRUPT theDOMImplementation: DOMImplementation -@disjoint_base class ElementInfo: __slots__ = ("_attr_info", "_model", "tagName") tagName: str @@ -67,7 +66,6 @@ class ExpatBuilder: def attlist_decl_handler(self, elem: str, name: str, type: str, default: str | None, required: bool) -> None: ... def xml_decl_handler(self, version: str, encoding: str | None, standalone: int) -> None: ... -@disjoint_base class FilterVisibilityController: __slots__ = ("filter",) filter: DOMBuilderFilter @@ -75,7 +73,6 @@ class FilterVisibilityController: def startContainer(self, node: Node) -> int: ... def acceptNode(self, node: Node) -> int: ... -@disjoint_base class FilterCrutch: __slots__ = ("_builder", "_level", "_old_start", "_old_end") def __init__(self, builder: ExpatBuilder) -> None: ... diff --git a/stdlib/xml/dom/minidom.pyi b/stdlib/xml/dom/minidom.pyi index 650557065dff..e0431417aa3c 100644 --- a/stdlib/xml/dom/minidom.pyi +++ b/stdlib/xml/dom/minidom.pyi @@ -4,7 +4,7 @@ from _typeshed import Incomplete, ReadableBuffer, SupportsRead, SupportsWrite from collections.abc import Iterable, Sequence from types import TracebackType from typing import Any, ClassVar, Generic, Literal, NoReturn, Protocol, TypeVar, overload, type_check_only -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias from xml.dom.minicompat import EmptyNodeList, NodeList from xml.dom.xmlbuilder import DocumentLS, DOMImplementationLS from xml.sax.xmlreader import XMLReader @@ -187,7 +187,6 @@ class DocumentFragment(Node): _AttrChildrenVar = TypeVar("_AttrChildrenVar", bound=_AttrChildren) _AttrChildrenPlusFragment = TypeVar("_AttrChildrenPlusFragment", bound=_AttrChildren | DocumentFragment) -@disjoint_base class Attr(Node): __slots__ = ("_name", "_value", "namespaceURI", "_prefix", "childNodes", "_localName", "ownerDocument", "ownerElement") nodeType: ClassVar[Literal[2]] @@ -232,7 +231,6 @@ class Attr(Node): # In the DOM, this interface isn't specific to Attr, but our implementation is # because that's the only place we use it. -@disjoint_base class NamedNodeMap: __slots__ = ("_attrs", "_attrsNS", "_ownerElement") def __init__(self, attrs: dict[str, Attr], attrsNS: dict[_NSName, Attr], ownerElement: Element) -> None: ... @@ -265,7 +263,6 @@ class NamedNodeMap: AttributeList = NamedNodeMap -@disjoint_base class TypeInfo: __slots__ = ("namespace", "name") namespace: str | None @@ -275,7 +272,6 @@ class TypeInfo: _ElementChildrenVar = TypeVar("_ElementChildrenVar", bound=_ElementChildren) _ElementChildrenPlusFragment = TypeVar("_ElementChildrenPlusFragment", bound=_ElementChildren | DocumentFragment) -@disjoint_base class Element(Node): __slots__ = ( "ownerDocument", @@ -368,7 +364,6 @@ class Childless: def normalize(self) -> None: ... def replaceChild(self, newChild: _NodesThatAreChildren | DocumentFragment, oldChild: _NodesThatAreChildren) -> NoReturn: ... -@disjoint_base class ProcessingInstruction(Childless, Node): __slots__ = ("target", "data") nodeType: ClassVar[Literal[7]] @@ -396,7 +391,6 @@ class ProcessingInstruction(Childless, Node): def __init__(self, target: str, data: str) -> None: ... def writexml(self, writer: SupportsWrite[str], indent: str = "", addindent: str = "", newl: str = "") -> None: ... -@disjoint_base class CharacterData(Childless, Node): __slots__ = ("_data", "ownerDocument", "parentNode", "previousSibling", "nextSibling") nodeValue: str @@ -487,7 +481,6 @@ class CDATASection(Text): def writexml(self, writer: SupportsWrite[str], indent: str = "", addindent: str = "", newl: str = "") -> None: ... -@disjoint_base class ReadOnlySequentialNamedNodeMap(Generic[_N]): __slots__ = ("_seq",) def __init__(self, seq: Sequence[_N] = ()) -> None: ... @@ -503,7 +496,6 @@ class ReadOnlySequentialNamedNodeMap(Generic[_N]): @property def length(self) -> int: ... -@disjoint_base class Identified: __slots__ = ("publicId", "systemId") publicId: str | None @@ -596,7 +588,6 @@ class DOMImplementation(DOMImplementationLS): def createDocumentType(self, qualifiedName: str | None, publicId: str | None, systemId: str | None) -> DocumentType: ... def getInterface(self, feature: str) -> Self | None: ... -@disjoint_base class ElementInfo: __slots__ = ("tagName",) tagName: str @@ -610,7 +601,6 @@ class ElementInfo: _DocumentChildrenPlusFragment = TypeVar("_DocumentChildrenPlusFragment", bound=_DocumentChildren | DocumentFragment) -@disjoint_base class Document(Node, DocumentLS): __slots__ = ("_elem_info", "doctype", "_id_search_stack", "childNodes", "_id_cache") nodeType: ClassVar[Literal[9]] diff --git a/stdlib/xml/dom/xmlbuilder.pyi b/stdlib/xml/dom/xmlbuilder.pyi index e5e6b3f13863..f19f7050b08d 100644 --- a/stdlib/xml/dom/xmlbuilder.pyi +++ b/stdlib/xml/dom/xmlbuilder.pyi @@ -1,6 +1,5 @@ from _typeshed import SupportsRead from typing import Any, Final, Literal, NoReturn -from typing_extensions import disjoint_base from xml.dom.minidom import Document, Node, _DOMErrorHandler __all__ = ["DOMBuilder", "DOMEntityResolver", "DOMInputSource"] @@ -44,12 +43,10 @@ class DOMBuilder: def parse(self, input: DOMInputSource) -> Document: ... def parseWithContext(self, input: DOMInputSource, cnode: Node, action: Literal[1, 2, 3, 4]) -> NoReturn: ... -@disjoint_base class DOMEntityResolver: __slots__ = ("_opener",) def resolveEntity(self, publicId: str | None, systemId: str) -> DOMInputSource: ... -@disjoint_base class DOMInputSource: __slots__ = ("byteStream", "characterStream", "stringData", "encoding", "publicId", "systemId", "baseURI") byteStream: SupportsRead[bytes] | None diff --git a/stdlib/zipfile/__init__.pyi b/stdlib/zipfile/__init__.pyi index 7c546d12e40e..e573d04dba05 100644 --- a/stdlib/zipfile/__init__.pyi +++ b/stdlib/zipfile/__init__.pyi @@ -6,7 +6,7 @@ from io import TextIOWrapper from os import PathLike from types import TracebackType from typing import IO, Final, Literal, Protocol, overload, type_check_only -from typing_extensions import Self, TypeAlias, disjoint_base +from typing_extensions import Self, TypeAlias __all__ = [ "BadZipFile", @@ -271,7 +271,6 @@ class PyZipFile(ZipFile): ) -> None: ... def writepy(self, pathname: str, basename: str = "", filterfunc: Callable[[str], bool] | None = None) -> None: ... -@disjoint_base class ZipInfo: __slots__ = ( "orig_filename", From a23c025b1d258609e5a6e70ea03b39531e050316 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 19:45:08 -0700 Subject: [PATCH 07/21] fixup --- .github/workflows/stubtest_stdlib.yml | 3 ++- stdlib/builtins.pyi | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index f6d8a91883c4..be68d875a821 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -46,7 +46,8 @@ jobs: check-latest: true - name: Install dependencies run: pip install -r requirements-tests.txt + # Temporary to get @disjoint_base support; can remove once mypy 1.18 is released - name: Install mypy from git - run: pip install git+https://github.com/python/mypy.git@657bdd84cff780a4b96c04525e2693c074a3fbf3 + run: pip install git+https://github.com/python/mypy.git@13fa6c3066612fcb38672c1002809dd5b08ac8e9 - name: Run stubtest run: python tests/stubtest_stdlib.py diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 02e42096dee6..9a31f553ea9c 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1021,7 +1021,8 @@ class slice(Generic[_StartT_co, _StopT_co, _StepT_co]): def indices(self, len: SupportsIndex, /) -> tuple[int, int, int]: ... -@disjoint_base +# Making this a disjoint_base upsets pyright +# @disjoint_base class tuple(Sequence[_T_co]): def __new__(cls, iterable: Iterable[_T_co] = ..., /) -> Self: ... def __len__(self) -> int: ... From 220281feddbdd97e622c381aec49e0ca385d913c Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 19:56:57 -0700 Subject: [PATCH 08/21] ? --- .github/workflows/stubtest_stdlib.yml | 2 +- stdlib/@tests/stubtest_allowlists/common.txt | 1 + stdlib/asyncio/graph.pyi | 36 +++++++++++--------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index be68d875a821..149aafe9a9e2 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -48,6 +48,6 @@ jobs: run: pip install -r requirements-tests.txt # Temporary to get @disjoint_base support; can remove once mypy 1.18 is released - name: Install mypy from git - run: pip install git+https://github.com/python/mypy.git@13fa6c3066612fcb38672c1002809dd5b08ac8e9 + run: pip install git+https://github.com/python/mypy.git@30a52639c7ac32e8d64906f3ba96d819f4785b3e - name: Run stubtest run: python tests/stubtest_stdlib.py diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 4462ada9107e..b1ecd553220c 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -13,6 +13,7 @@ tkinter.simpledialog.[A-Z_]+ tkinter.simpledialog.TclVersion tkinter.simpledialog.TkVersion tkinter.Text.count # stubtest somehow thinks that index1 parameter has a default value, but it doesn't in any of the overloads +builtins.tuple # should have @disjoint_base but hits pyright issue # =============================================================== diff --git a/stdlib/asyncio/graph.pyi b/stdlib/asyncio/graph.pyi index 69d23c021552..18a8a6457d75 100644 --- a/stdlib/asyncio/graph.pyi +++ b/stdlib/asyncio/graph.pyi @@ -1,26 +1,28 @@ +import sys from _typeshed import SupportsWrite from asyncio import Future from dataclasses import dataclass from types import FrameType from typing import Any, overload -__all__ = ("capture_call_graph", "format_call_graph", "print_call_graph", "FrameCallGraphEntry", "FutureCallGraph") +if sys.version_info >= (3, 14): + __all__ = ("capture_call_graph", "format_call_graph", "print_call_graph", "FrameCallGraphEntry", "FutureCallGraph") -@dataclass(frozen=True, slots=True) -class FrameCallGraphEntry: - frame: FrameType + @dataclass(frozen=True, slots=True) + class FrameCallGraphEntry: + frame: FrameType -@dataclass(frozen=True, slots=True) -class FutureCallGraph: - future: Future[Any] - call_stack: tuple[FrameCallGraphEntry, ...] - awaited_by: tuple[FutureCallGraph, ...] + @dataclass(frozen=True, slots=True) + class FutureCallGraph: + future: Future[Any] + call_stack: tuple[FrameCallGraphEntry, ...] + awaited_by: tuple[FutureCallGraph, ...] -@overload -def capture_call_graph(future: None = None, /, *, depth: int = 1, limit: int | None = None) -> FutureCallGraph | None: ... -@overload -def capture_call_graph(future: Future[Any], /, *, depth: int = 1, limit: int | None = None) -> FutureCallGraph | None: ... -def format_call_graph(future: Future[Any] | None = None, /, *, depth: int = 1, limit: int | None = None) -> str: ... -def print_call_graph( - future: Future[Any] | None = None, /, *, file: SupportsWrite[str] | None = None, depth: int = 1, limit: int | None = None -) -> None: ... + @overload + def capture_call_graph(future: None = None, /, *, depth: int = 1, limit: int | None = None) -> FutureCallGraph | None: ... + @overload + def capture_call_graph(future: Future[Any], /, *, depth: int = 1, limit: int | None = None) -> FutureCallGraph | None: ... + def format_call_graph(future: Future[Any] | None = None, /, *, depth: int = 1, limit: int | None = None) -> str: ... + def print_call_graph( + future: Future[Any] | None = None, /, *, file: SupportsWrite[str] | None = None, depth: int = 1, limit: int | None = None + ) -> None: ... From b76c6401244e8f0c0ca20e8e8d5fbe8dc8e3447e Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 20:02:28 -0700 Subject: [PATCH 09/21] add some missing slots --- stdlib/importlib/metadata/__init__.pyi | 4 +++- stdlib/typing_extensions.pyi | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/stdlib/importlib/metadata/__init__.pyi b/stdlib/importlib/metadata/__init__.pyi index f9d3792565cb..6248554d7c2a 100644 --- a/stdlib/importlib/metadata/__init__.pyi +++ b/stdlib/importlib/metadata/__init__.pyi @@ -115,10 +115,12 @@ if sys.version_info >= (3, 12): def groups(self) -> set[str]: ... elif sys.version_info >= (3, 10): - class DeprecatedList(list[_T]): ... + class DeprecatedList(list[_T]): + __slots__ = () class EntryPoints(DeprecatedList[EntryPoint]): # use as list is deprecated since 3.10 # int argument is deprecated since 3.10 + __slots__ = () def __getitem__(self, name: int | str) -> EntryPoint: ... # type: ignore[override] def select( self, diff --git a/stdlib/typing_extensions.pyi b/stdlib/typing_extensions.pyi index 4cc353dd5c1d..f5ea13f67733 100644 --- a/stdlib/typing_extensions.pyi +++ b/stdlib/typing_extensions.pyi @@ -408,36 +408,43 @@ else: @runtime_checkable class SupportsInt(Protocol, metaclass=abc.ABCMeta): + __slots__ = () @abc.abstractmethod def __int__(self) -> int: ... @runtime_checkable class SupportsFloat(Protocol, metaclass=abc.ABCMeta): + __slots__ = () @abc.abstractmethod def __float__(self) -> float: ... @runtime_checkable class SupportsComplex(Protocol, metaclass=abc.ABCMeta): + __slots__ = () @abc.abstractmethod def __complex__(self) -> complex: ... @runtime_checkable class SupportsBytes(Protocol, metaclass=abc.ABCMeta): + __slots__ = () @abc.abstractmethod def __bytes__(self) -> bytes: ... @runtime_checkable class SupportsIndex(Protocol, metaclass=abc.ABCMeta): + __slots__ = () @abc.abstractmethod def __index__(self) -> int: ... @runtime_checkable class SupportsAbs(Protocol[_T_co]): + __slots__ = () @abc.abstractmethod def __abs__(self) -> _T_co: ... @runtime_checkable class SupportsRound(Protocol[_T_co]): + __slots__ = () @overload @abc.abstractmethod def __round__(self) -> int: ... From 482fdd0e47a6d4ce66ac98ff4af0686dadfd69a6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 20:03:44 -0700 Subject: [PATCH 10/21] AttributeError and NameError were not disjoint bases in 3.9 --- stdlib/builtins.pyi | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 9a31f553ea9c..f2ce8a60ccbf 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -2088,13 +2088,16 @@ if sys.platform == "win32": class ArithmeticError(Exception): ... class AssertionError(Exception): ... -@disjoint_base -class AttributeError(Exception): - if sys.version_info >= (3, 10): +if sys.version_info >= (3, 10): + @disjoint_base + class AttributeError(Exception): def __init__(self, *args: object, name: str | None = ..., obj: object = ...) -> None: ... name: str obj: object +else: + class AttributeError(Exception): ... + class BufferError(Exception): ... class EOFError(Exception): ... @@ -2110,12 +2113,15 @@ class ImportError(Exception): class LookupError(Exception): ... class MemoryError(Exception): ... -@disjoint_base -class NameError(Exception): - if sys.version_info >= (3, 10): +if sys.version_info >= (3, 10): + @disjoint_base + class NameError(Exception): def __init__(self, *args: object, name: str | None = ...) -> None: ... name: str +else: + class NameError(Exception): ... + class ReferenceError(Exception): ... class RuntimeError(Exception): ... class StopAsyncIteration(Exception): ... From 950c2d78cfa487baf281cf19436d0429597d5138 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 20:17:42 -0700 Subject: [PATCH 11/21] fix EntryPoint --- stdlib/importlib/metadata/__init__.pyi | 56 ++++++++++++++++++-------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/stdlib/importlib/metadata/__init__.pyi b/stdlib/importlib/metadata/__init__.pyi index 6248554d7c2a..98b113d476fa 100644 --- a/stdlib/importlib/metadata/__init__.pyi +++ b/stdlib/importlib/metadata/__init__.pyi @@ -11,7 +11,7 @@ from os import PathLike from pathlib import Path from re import Pattern from typing import Any, ClassVar, Generic, NamedTuple, TypeVar, overload -from typing_extensions import Self, TypeAlias, deprecated +from typing_extensions import Self, TypeAlias, deprecated, disjoint_base _T = TypeVar("_T") _KT = TypeVar("_KT") @@ -59,23 +59,21 @@ else: value: str group: str -class EntryPoint(_EntryPointBase): - pattern: ClassVar[Pattern[str]] - if sys.version_info >= (3, 11): +if sys.version_info >= (3, 11): + class EntryPoint(_EntryPointBase): + pattern: ClassVar[Pattern[str]] name: str value: str group: str def __init__(self, name: str, value: str, group: str) -> None: ... - - def load(self) -> Any: ... # Callable[[], Any] or an importable module - @property - def extras(self) -> list[str]: ... - @property - def module(self) -> str: ... - @property - def attr(self) -> str: ... - if sys.version_info >= (3, 10): + def load(self) -> Any: ... # Callable[[], Any] or an importable module + @property + def extras(self) -> list[str]: ... + @property + def module(self) -> str: ... + @property + def attr(self) -> str: ... dist: ClassVar[Distribution | None] def matches( self, @@ -87,12 +85,36 @@ class EntryPoint(_EntryPointBase): attr: str = ..., extras: list[str] = ..., ) -> bool: ... # undocumented - - def __hash__(self) -> int: ... - if sys.version_info >= (3, 11): + def __hash__(self) -> int: ... def __eq__(self, other: object) -> bool: ... def __lt__(self, other: object) -> bool: ... - if sys.version_info < (3, 12): + +else: + @disjoint_base + class EntryPoint(_EntryPointBase): + pattern: ClassVar[Pattern[str]] + + def load(self) -> Any: ... # Callable[[], Any] or an importable module + @property + def extras(self) -> list[str]: ... + @property + def module(self) -> str: ... + @property + def attr(self) -> str: ... + if sys.version_info >= (3, 10): + dist: ClassVar[Distribution | None] + def matches( + self, + *, + name: str = ..., + value: str = ..., + group: str = ..., + module: str = ..., + attr: str = ..., + extras: list[str] = ..., + ) -> bool: ... # undocumented + + def __hash__(self) -> int: ... def __iter__(self) -> Iterator[Any]: ... # result of iter((str, Self)), really if sys.version_info >= (3, 12): From 00733113a7c45dfe7be1edbfcbcdc444b398c6e4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Thu, 21 Aug 2025 21:02:59 -0700 Subject: [PATCH 12/21] put one back --- stdlib/importlib/metadata/__init__.pyi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/stdlib/importlib/metadata/__init__.pyi b/stdlib/importlib/metadata/__init__.pyi index 98b113d476fa..6c9a8d6a31f6 100644 --- a/stdlib/importlib/metadata/__init__.pyi +++ b/stdlib/importlib/metadata/__init__.pyi @@ -88,6 +88,8 @@ if sys.version_info >= (3, 11): def __hash__(self) -> int: ... def __eq__(self, other: object) -> bool: ... def __lt__(self, other: object) -> bool: ... + if sys.version_info < (3, 12): + def __iter__(self) -> Iterator[Any]: ... # result of iter((str, Self)), really else: @disjoint_base From fcb681357383503a216e943c0ec0a1741e97e3da Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 22 Aug 2025 09:07:20 -0700 Subject: [PATCH 13/21] fixes --- stdlib/ssl.pyi | 47 ++++++++-------------------------------------- stdlib/tarfile.pyi | 26 +++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 41 deletions(-) diff --git a/stdlib/ssl.pyi b/stdlib/ssl.pyi index 8c41e53f10a9..faa98cb39920 100644 --- a/stdlib/ssl.pyi +++ b/stdlib/ssl.pyi @@ -28,7 +28,7 @@ from _ssl import ( from _typeshed import ReadableBuffer, StrOrBytesPath, WriteableBuffer from collections.abc import Callable, Iterable from typing import Any, Final, Literal, NamedTuple, TypedDict, overload, type_check_only -from typing_extensions import Never, Self, TypeAlias, deprecated, disjoint_base +from typing_extensions import Never, Self, TypeAlias, deprecated if sys.version_info >= (3, 13): from _ssl import HAS_PSK as HAS_PSK @@ -287,44 +287,13 @@ class _ASN1Object(_ASN1ObjectBase): @classmethod def fromname(cls, name: str) -> Self: ... -if sys.version_info >= (3, 12): - class Purpose(_ASN1Object, enum.Enum): - # Normally this class would inherit __new__ from _ASN1Object, but - # because this is an enum, the inherited __new__ is replaced at runtime with - # Enum.__new__. - def __new__(cls, value: object) -> Self: ... - SERVER_AUTH = ( - 129, - "serverAuth", - "TLS Web Server Authentication", - "1.3.6.1.5.5.7.3.2", - ) # pyright: ignore[reportCallIssue] - CLIENT_AUTH = ( - 130, - "clientAuth", - "TLS Web Client Authentication", - "1.3.6.1.5.5.7.3.1", - ) # pyright: ignore[reportCallIssue] - -else: - @disjoint_base - class Purpose(_ASN1Object, enum.Enum): - # Normally this class would inherit __new__ from _ASN1Object, but - # because this is an enum, the inherited __new__ is replaced at runtime with - # Enum.__new__. - def __new__(cls, value: object) -> Self: ... - SERVER_AUTH = ( - 129, - "serverAuth", - "TLS Web Server Authentication", - "1.3.6.1.5.5.7.3.2", - ) # pyright: ignore[reportCallIssue] - CLIENT_AUTH = ( - 130, - "clientAuth", - "TLS Web Client Authentication", - "1.3.6.1.5.5.7.3.1", - ) # pyright: ignore[reportCallIssue] +class Purpose(_ASN1Object, enum.Enum): + # Normally this class would inherit __new__ from _ASN1Object, but + # because this is an enum, the inherited __new__ is replaced at runtime with + # Enum.__new__. + def __new__(cls, value: object) -> Self: ... + SERVER_AUTH = (129, "serverAuth", "TLS Web Server Authentication", "1.3.6.1.5.5.7.3.2") # pyright: ignore[reportCallIssue] + CLIENT_AUTH = (130, "clientAuth", "TLS Web Client Authentication", "1.3.6.1.5.5.7.3.1") # pyright: ignore[reportCallIssue] class SSLSocket(socket.socket): context: SSLContext diff --git a/stdlib/tarfile.pyi b/stdlib/tarfile.pyi index c987369e57c3..f6623ea9929d 100644 --- a/stdlib/tarfile.pyi +++ b/stdlib/tarfile.pyi @@ -7,7 +7,7 @@ from collections.abc import Callable, Iterable, Iterator, Mapping from gzip import _ReadableFileobj as _GzipReadableFileobj, _WritableFileobj as _GzipWritableFileobj from types import TracebackType from typing import IO, ClassVar, Final, Literal, Protocol, overload, type_check_only -from typing_extensions import Self, TypeAlias, deprecated, disjoint_base +from typing_extensions import Self, TypeAlias, deprecated if sys.version_info >= (3, 14): from compression.zstd import ZstdDict @@ -742,8 +742,30 @@ class LinkFallbackError(FilterError): def fully_trusted_filter(member: TarInfo, dest_path: str) -> TarInfo: ... def tar_filter(member: TarInfo, dest_path: str) -> TarInfo: ... def data_filter(member: TarInfo, dest_path: str) -> TarInfo: ... -@disjoint_base + class TarInfo: + __slots__ = ( + "name", + "mode", + "uid", + "gid", + "size", + "mtime", + "chksum", + "type", + "linkname", + "uname", + "gname", + "devmajor", + "devminor", + "offset", + "offset_data", + "pax_headers", + "sparse", + "_tarfile", + "_sparse_structs", + "_link_target", + ) name: str path: str size: int From 7d2b0f4e95a89b5f3b417e7eaafc521360e48649 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 22 Aug 2025 09:08:02 -0700 Subject: [PATCH 14/21] mine --- .github/workflows/stubtest_stdlib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index 149aafe9a9e2..0233ac14ed70 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -48,6 +48,6 @@ jobs: run: pip install -r requirements-tests.txt # Temporary to get @disjoint_base support; can remove once mypy 1.18 is released - name: Install mypy from git - run: pip install git+https://github.com/python/mypy.git@30a52639c7ac32e8d64906f3ba96d819f4785b3e + run: pip install git+https://github.com/JelleZijlstra/mypy.git@03ce7f0f0ece2b0dbcda701f6df1488eda484363 - name: Run stubtest run: python tests/stubtest_stdlib.py From 9bb5a56630e3be6150e6a1f54d8ce1446d935ac0 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Fri, 22 Aug 2025 09:10:30 -0700 Subject: [PATCH 15/21] allowlist --- stdlib/@tests/stubtest_allowlists/common.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index b1ecd553220c..1bd960313434 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -14,7 +14,7 @@ tkinter.simpledialog.TclVersion tkinter.simpledialog.TkVersion tkinter.Text.count # stubtest somehow thinks that index1 parameter has a default value, but it doesn't in any of the overloads builtins.tuple # should have @disjoint_base but hits pyright issue - +tarfile.TarInfo.__slots__ # it's a big dictionary at runtime and the dictionary values are a bit long # =============================================================== # TODO: Modules that exist at runtime, but are missing from stubs From 7ae12e82f7b031f4e6fda2d11d2ba551e8f03810 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 24 Aug 2025 06:14:17 -0700 Subject: [PATCH 16/21] fix stragglers --- stdlib/@tests/stubtest_allowlists/common.txt | 1 + stdlib/_zstd.pyi | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 1bd960313434..3a5e5d16862f 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -16,6 +16,7 @@ tkinter.Text.count # stubtest somehow thinks that index1 parameter has a defaul builtins.tuple # should have @disjoint_base but hits pyright issue tarfile.TarInfo.__slots__ # it's a big dictionary at runtime and the dictionary values are a bit long + # =============================================================== # TODO: Modules that exist at runtime, but are missing from stubs # =============================================================== diff --git a/stdlib/_zstd.pyi b/stdlib/_zstd.pyi index cf75ad89a35f..f5e98ef88bb9 100644 --- a/stdlib/_zstd.pyi +++ b/stdlib/_zstd.pyi @@ -46,7 +46,7 @@ class ZstdCompressor: FLUSH_BLOCK: Final = 1 FLUSH_FRAME: Final = 2 def __new__( - self, level: int | None = None, options: Mapping[int, int] | None = None, zstd_dict: ZstdDict | None = None + cls, level: int | None = None, options: Mapping[int, int] | None = None, zstd_dict: ZstdDict | None = None ) -> Self: ... def compress( self, /, data: ReadableBuffer, mode: _ZstdCompressorContinue | _ZstdCompressorFlushBlock | _ZstdCompressorFlushFrame = 0 @@ -58,7 +58,7 @@ class ZstdCompressor: @final class ZstdDecompressor: - def __new__(self, zstd_dict: ZstdDict | None = None, options: Mapping[int, int] | None = None) -> Self: ... + def __new__(cls, zstd_dict: ZstdDict | None = None, options: Mapping[int, int] | None = None) -> Self: ... def decompress(self, /, data: ReadableBuffer, max_length: int = -1) -> bytes: ... @property def eof(self) -> bool: ... @@ -69,7 +69,7 @@ class ZstdDecompressor: @final class ZstdDict: - def __new__(self, dict_content: bytes, /, *, is_raw: bool = False) -> Self: ... + def __new__(cls, dict_content: bytes, /, *, is_raw: bool = False) -> Self: ... def __len__(self, /) -> int: ... @property def as_digested_dict(self) -> tuple[Self, int]: ... From aca41890d853020c0ac90137901d85ef308420e6 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 24 Aug 2025 06:14:43 -0700 Subject: [PATCH 17/21] mypy pin --- .github/workflows/stubtest_stdlib.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/stubtest_stdlib.yml b/.github/workflows/stubtest_stdlib.yml index 0233ac14ed70..9648fac32061 100644 --- a/.github/workflows/stubtest_stdlib.yml +++ b/.github/workflows/stubtest_stdlib.yml @@ -48,6 +48,6 @@ jobs: run: pip install -r requirements-tests.txt # Temporary to get @disjoint_base support; can remove once mypy 1.18 is released - name: Install mypy from git - run: pip install git+https://github.com/JelleZijlstra/mypy.git@03ce7f0f0ece2b0dbcda701f6df1488eda484363 + run: pip install git+https://github.com/python/mypy.git@116b92bae7b5dbf5e6bd36fd9b0c6804973e5554 - name: Run stubtest run: python tests/stubtest_stdlib.py From aa2cbd3ac49f3baa1028770ef9ecbc25216396f2 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 24 Aug 2025 06:21:49 -0700 Subject: [PATCH 18/21] unused allowlists --- stdlib/@tests/stubtest_allowlists/common.txt | 18 ------------------ stdlib/@tests/stubtest_allowlists/darwin.txt | 1 - stdlib/@tests/stubtest_allowlists/py310.txt | 1 - stdlib/@tests/stubtest_allowlists/py311.txt | 1 - stdlib/@tests/stubtest_allowlists/py39.txt | 1 - stdlib/@tests/stubtest_allowlists/win32.txt | 4 ---- 6 files changed, 26 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index 3a5e5d16862f..b9cb4f3f13f6 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -4,15 +4,12 @@ # Please keep sorted alphabetically -collections\.ChainMap\.fromkeys # https://github.com/python/mypy/issues/17023 -http.client.HTTPConnection.response_class # the actual type at runtime is abc.ABCMeta importlib.abc.Loader.exec_module # See Lib/importlib/_abc.py. Might be defined for backwards compatibility importlib.abc.MetaPathFinder.find_spec # Not defined on the actual class, but expected to exist. importlib.abc.PathEntryFinder.find_spec # Not defined on the actual class, but expected to exist. tkinter.simpledialog.[A-Z_]+ tkinter.simpledialog.TclVersion tkinter.simpledialog.TkVersion -tkinter.Text.count # stubtest somehow thinks that index1 parameter has a default value, but it doesn't in any of the overloads builtins.tuple # should have @disjoint_base but hits pyright issue tarfile.TarInfo.__slots__ # it's a big dictionary at runtime and the dictionary values are a bit long @@ -203,7 +200,6 @@ _markupbase.ParserBase.parse_marked_section _pydecimal.* # See comments in file _typeshed.* # Utility types for typeshed, doesn't exist at runtime -argparse.ArgumentParser.__init__ # stubtest doesn't recognise the runtime default (a class) as being compatible with a callback protocol (the stub annotation) argparse.Namespace.__getattr__ # The whole point of this class is its attributes are dynamic # Runtime AST node runtime constructor behaviour is too loose. @@ -220,8 +216,6 @@ argparse.Namespace.__setattr__ # should allow setting any attribute ast.ImportFrom.level # None on the class, but never None on instances ast.NodeVisitor.visit_\w+ # Methods are discovered dynamically, see #3796 -_?asyncio.Future.__init__ # Usually initialized from c object -asyncio.futures.Future.__init__ # Usually initialized from c object # Condition functions are exported in __init__ asyncio.Condition.acquire @@ -232,7 +226,6 @@ asyncio.locks.Condition.locked asyncio.locks.Condition.release builtins.memoryview.__contains__ # C type that implements __getitem__ -builtins.object.__init__ # default C signature is incorrect builtins.reveal_locals # Builtins that type checkers pretends exist builtins.reveal_type # Builtins that type checkers pretends exist builtins.type.__dict__ # read-only but not actually a property; stubtest thinks it's a mutable attribute. @@ -262,8 +255,6 @@ configparser.SectionProxy.getint # SectionProxy get functions are set in __init contextlib.AbstractAsyncContextManager.__class_getitem__ contextlib.AbstractContextManager.__class_getitem__ -_?contextvars.Context.__init__ # C signature is broader than what is actually accepted - copy.PyStringMap # defined only in Jython # The Dialect properties are initialized as None in Dialect but their values are enforced in _Dialect @@ -331,9 +322,6 @@ importlib.machinery.ExtensionFileLoader.get_filename inspect.Parameter.__init__ inspect.Signature.__init__ -inspect.Parameter.empty # set as private marker _empty -inspect.Signature.empty # set as private marker _empty - logging.LogRecord.__setattr__ # doesn't exist, but makes things easy if we pretend it does # Iterable classes that don't define __iter__ at runtime (usually iterable via __getitem__) @@ -379,11 +367,6 @@ multiprocessing.queues.JoinableQueue.__init__ multiprocessing.queues.Queue.__init__ multiprocessing.queues.SimpleQueue.__init__ -# alias for a class defined elsewhere, -# mypy infers the variable has type `(*args) -> ForkingPickler` -# but stubtest infers the runtime type as -multiprocessing.reduction.AbstractReducer.ForkingPickler - # These methods are dynamically created after object initialization, # copied from a wrapped lock object. Stubtest doesn't think they exist # because of that. @@ -408,7 +391,6 @@ os.PathLike.__class_getitem__ # PathLike is a protocol; we don't expect all Pat pickle._Pickler\..* # Best effort typing for undocumented internals pickle._Unpickler\..* # Best effort typing for undocumented internals -_?queue.SimpleQueue.__init__ # C signature is broader than what is actually accepted shutil.rmtree # function with attributes, which we approximate with a callable protocol socketserver.BaseServer.get_request # Not implemented, but expected to exist on subclasses. ssl.PROTOCOL_SSLv2 # Depends on the existence and flags of SSL diff --git a/stdlib/@tests/stubtest_allowlists/darwin.txt b/stdlib/@tests/stubtest_allowlists/darwin.txt index e02468b6b6c9..b82f42156ad0 100644 --- a/stdlib/@tests/stubtest_allowlists/darwin.txt +++ b/stdlib/@tests/stubtest_allowlists/darwin.txt @@ -43,7 +43,6 @@ curses.LINES # Initialized only after initscr call curses.has_key # stubtest gets confused because this is both a module and a function in curses multiprocessing.popen_spawn_win32 # exists on Darwin but fails to import readline.append_history_file # Only available if compiled with GNU readline, not editline -select.kqueue.__init__ # default C signature is wrong select.poll # Actually a function; we have a class so it can be used as a type # Some of these exist on non-windows, but they are useless and this is not intended diff --git a/stdlib/@tests/stubtest_allowlists/py310.txt b/stdlib/@tests/stubtest_allowlists/py310.txt index bb75541d1c98..c02b0aac20cd 100644 --- a/stdlib/@tests/stubtest_allowlists/py310.txt +++ b/stdlib/@tests/stubtest_allowlists/py310.txt @@ -100,7 +100,6 @@ typing_extensions.Sentinel.__call__ # <= 3.11 # ======= -_?bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set enum.Enum._generate_next_value_ importlib.abc.Finder.find_module urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified diff --git a/stdlib/@tests/stubtest_allowlists/py311.txt b/stdlib/@tests/stubtest_allowlists/py311.txt index e9ccc238b37c..a96475d48265 100644 --- a/stdlib/@tests/stubtest_allowlists/py311.txt +++ b/stdlib/@tests/stubtest_allowlists/py311.txt @@ -68,7 +68,6 @@ importlib.metadata._meta.SimplePath.__truediv__ # Runtime definition of protoco # <= 3.11 # ======= -_?bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set enum.Enum._generate_next_value_ importlib.abc.Finder.find_module urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified diff --git a/stdlib/@tests/stubtest_allowlists/py39.txt b/stdlib/@tests/stubtest_allowlists/py39.txt index 6e62d3a07f61..f706ee5c19ee 100644 --- a/stdlib/@tests/stubtest_allowlists/py39.txt +++ b/stdlib/@tests/stubtest_allowlists/py39.txt @@ -54,7 +54,6 @@ typing_extensions.Sentinel.__call__ # <= 3.11 # ======= -_?bz2.BZ2Decompressor.__init__ # function does not accept parameters but C signature is set enum.Enum._generate_next_value_ importlib.abc.Finder.find_module urllib.request.HTTPPasswordMgrWithPriorAuth.__init__ # Args are passed as is to super, so super args are specified diff --git a/stdlib/@tests/stubtest_allowlists/win32.txt b/stdlib/@tests/stubtest_allowlists/win32.txt index ec42a17db226..66695e1d87d3 100644 --- a/stdlib/@tests/stubtest_allowlists/win32.txt +++ b/stdlib/@tests/stubtest_allowlists/win32.txt @@ -2,10 +2,6 @@ # TODO: Allowlist entries that should be fixed # ============================================ -# alias for a class defined elsewhere, -# mypy infers the variable has type `(*args) -> DupHandle` but stubtest infers the runtime type as -multiprocessing.reduction.AbstractReducer.DupHandle - # Exists at runtime, but missing from stubs _winapi.CreateFileMapping _winapi.MapViewOfFile From 622f17ff9e465d43f2c2a7bf37e020d341a1f456 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 24 Aug 2025 06:32:16 -0700 Subject: [PATCH 19/21] more stubtest fixes --- stdlib/_random.pyi | 2 +- stdlib/asyncio/windows_events.pyi | 2 +- stdlib/collections/__init__.pyi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/_random.pyi b/stdlib/_random.pyi index ac00fdfb7272..b473c6858ae0 100644 --- a/stdlib/_random.pyi +++ b/stdlib/_random.pyi @@ -6,7 +6,7 @@ _State: TypeAlias = tuple[int, ...] @disjoint_base class Random: - if sys.version_info >= (3, 10): + if sys.version_info >= (3, 11): def __init__(self, seed: object = ..., /) -> None: ... else: def __new__(self, seed: object = ..., /) -> Self: ... diff --git a/stdlib/asyncio/windows_events.pyi b/stdlib/asyncio/windows_events.pyi index b454aca1f262..a32381bfb3e6 100644 --- a/stdlib/asyncio/windows_events.pyi +++ b/stdlib/asyncio/windows_events.pyi @@ -116,6 +116,6 @@ if sys.platform == "win32": if sys.version_info >= (3, 14): _DefaultEventLoopPolicy = _WindowsProactorEventLoopPolicy else: - DefaultEventLoopPolicy = WindowsSelectorEventLoopPolicy + DefaultEventLoopPolicy = WindowsProactorEventLoopPolicy if sys.version_info >= (3, 13): EventLoop = ProactorEventLoop diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index 2df6c67d5bff..10738952894f 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -482,7 +482,7 @@ class ChainMap(MutableMapping[_KT, _VT]): # so the signature should be kept in line with `dict.fromkeys`. @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T]) -> ChainMap[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_T], /) -> ChainMap[_T, Any | None]: ... @classmethod @overload # Special-case None: the user probably wants to add non-None values later. From e480d919ca97113b8cf78c8eaafd8f78ddda84d1 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 24 Aug 2025 06:36:24 -0700 Subject: [PATCH 20/21] only pos-only in 3.13+ --- stdlib/collections/__init__.pyi | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index 10738952894f..8636e6cdbdc3 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -480,9 +480,15 @@ class ChainMap(MutableMapping[_KT, _VT]): __copy__ = copy # All arguments to `fromkeys` are passed to `dict.fromkeys` at runtime, # so the signature should be kept in line with `dict.fromkeys`. - @classmethod - @overload - def fromkeys(cls, iterable: Iterable[_T], /) -> ChainMap[_T, Any | None]: ... + if sys.version_info >= (3, 13): + @classmethod + @overload + def fromkeys(cls, iterable: Iterable[_T], /) -> ChainMap[_T, Any | None]: ... + else: + @classmethod + @overload + def fromkeys(cls, iterable: Iterable[_T]) -> ChainMap[_T, Any | None]: ... + @classmethod @overload # Special-case None: the user probably wants to add non-None values later. From a17c86bef4240c5286aa8b5cebbac659b33942b4 Mon Sep 17 00:00:00 2001 From: Jelle Zijlstra Date: Sun, 24 Aug 2025 06:45:58 -0700 Subject: [PATCH 21/21] ignore the Random thing for now --- stdlib/@tests/stubtest_allowlists/py310.txt | 2 ++ stdlib/_random.pyi | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/stdlib/@tests/stubtest_allowlists/py310.txt b/stdlib/@tests/stubtest_allowlists/py310.txt index c02b0aac20cd..79b7f5787451 100644 --- a/stdlib/@tests/stubtest_allowlists/py310.txt +++ b/stdlib/@tests/stubtest_allowlists/py310.txt @@ -55,6 +55,8 @@ asyncio.locks.Lock.__init__ asyncio.locks.Semaphore.__init__ asyncio.queues.Queue.__init__ +_random.Random.__init__ # Issues with __new__/__init__ correspondence + bdb.Breakpoint.clearBreakpoints # Exists at runtime, but missing from stubs diff --git a/stdlib/_random.pyi b/stdlib/_random.pyi index b473c6858ae0..ac00fdfb7272 100644 --- a/stdlib/_random.pyi +++ b/stdlib/_random.pyi @@ -6,7 +6,7 @@ _State: TypeAlias = tuple[int, ...] @disjoint_base class Random: - if sys.version_info >= (3, 11): + if sys.version_info >= (3, 10): def __init__(self, seed: object = ..., /) -> None: ... else: def __new__(self, seed: object = ..., /) -> Self: ...