From 7e16c80989fba7c7e97052af7484065f3d58aab7 Mon Sep 17 00:00:00 2001 From: Sebastian Rittau Date: Sun, 27 Jul 2025 12:56:26 +0200 Subject: [PATCH] Remove some pytype workarounds from stdlib (#14470) Co-authored-by: Alex Waygood Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- stdlib/@tests/stubtest_allowlists/common.txt | 2 -- stdlib/asyncio/base_futures.pyi | 8 +++----- stdlib/asyncio/futures.pyi | 8 ++------ stdlib/builtins.pyi | 1 - stdlib/optparse.pyi | 3 +-- stdlib/re.pyi | 4 +--- stdlib/typing_extensions.pyi | 10 +--------- stdlib/unittest/case.pyi | 14 ++------------ 8 files changed, 10 insertions(+), 40 deletions(-) diff --git a/stdlib/@tests/stubtest_allowlists/common.txt b/stdlib/@tests/stubtest_allowlists/common.txt index e222a340c..3de125744 100644 --- a/stdlib/@tests/stubtest_allowlists/common.txt +++ b/stdlib/@tests/stubtest_allowlists/common.txt @@ -470,7 +470,6 @@ typing(_extensions)?\.Generic typing(_extensions)?\.TypedDict typing_extensions\.ParamSpec.* typing_extensions\.TypeVar.* -typing_extensions\._SpecialForm.* # Special primitives typing(_extensions)?\.AbstractSet @@ -499,7 +498,6 @@ typing(_extensions)?\.Reversible typing(_extensions)?\.Sequence typing(_extensions)?\.Sized typing(_extensions)?\.ValuesView -typing_extensions\.Final typing_extensions\.LiteralString # Typing-related weirdness diff --git a/stdlib/asyncio/base_futures.pyi b/stdlib/asyncio/base_futures.pyi index 55d2fbdbd..2cd0f2e3a 100644 --- a/stdlib/asyncio/base_futures.pyi +++ b/stdlib/asyncio/base_futures.pyi @@ -1,19 +1,17 @@ +from _asyncio import Future from collections.abc import Callable, Sequence from contextvars import Context from typing import Any, Final +from typing_extensions import TypeIs from . import futures __all__ = () -# asyncio defines 'isfuture()' in base_futures.py and re-imports it in futures.py -# but it leads to circular import error in pytype tool. -# That's why the import order is reversed. -from .futures import isfuture as isfuture - _PENDING: Final = "PENDING" # undocumented _CANCELLED: Final = "CANCELLED" # undocumented _FINISHED: Final = "FINISHED" # undocumented +def isfuture(obj: object) -> TypeIs[Future[Any]]: ... def _format_callbacks(cb: Sequence[tuple[Callable[[futures.Future[Any]], None], Context]]) -> str: ... # undocumented def _future_repr_info(future: futures.Future[Any]) -> list[str]: ... # undocumented diff --git a/stdlib/asyncio/futures.pyi b/stdlib/asyncio/futures.pyi index 644d2d0e9..c907c7036 100644 --- a/stdlib/asyncio/futures.pyi +++ b/stdlib/asyncio/futures.pyi @@ -1,9 +1,9 @@ import sys from _asyncio import Future as Future from concurrent.futures._base import Future as _ConcurrentFuture -from typing import Any, TypeVar -from typing_extensions import TypeIs +from typing import TypeVar +from .base_futures import isfuture as isfuture from .events import AbstractEventLoop # Keep asyncio.__all__ updated with any changes to __all__ here @@ -16,8 +16,4 @@ else: _T = TypeVar("_T") -# asyncio defines 'isfuture()' in base_futures.py and re-imports it in futures.py -# but it leads to circular import error in pytype tool. -# That's why the import order is reversed. -def isfuture(obj: object) -> TypeIs[Future[Any]]: ... def wrap_future(future: _ConcurrentFuture[_T] | Future[_T], *, loop: AbstractEventLoop | None = None) -> Future[_T]: ... diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index a5532cd4a..4b1c4b68b 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1526,7 +1526,6 @@ def iter(object: Callable[[], _T | None], sentinel: None, /) -> Iterator[_T]: .. @overload def iter(object: Callable[[], _T], sentinel: object, /) -> Iterator[_T]: ... -# Keep this alias in sync with unittest.case._ClassInfo if sys.version_info >= (3, 10): _ClassInfo: TypeAlias = type | types.UnionType | tuple[_ClassInfo, ...] else: diff --git a/stdlib/optparse.pyi b/stdlib/optparse.pyi index 8b7fcd82e..c52291799 100644 --- a/stdlib/optparse.pyi +++ b/stdlib/optparse.pyi @@ -24,8 +24,7 @@ __all__ = [ "BadOptionError", "check_choice", ] -# pytype is not happy with `NO_DEFAULT: Final = ("NO", "DEFAULT")` -NO_DEFAULT: Final[tuple[Literal["NO"], Literal["DEFAULT"]]] +NO_DEFAULT: Final = ("NO", "DEFAULT") SUPPRESS_HELP: Final = "SUPPRESSHELP" SUPPRESS_USAGE: Final = "SUPPRESSUSAGE" diff --git a/stdlib/re.pyi b/stdlib/re.pyi index f25a0a376..b080626c5 100644 --- a/stdlib/re.pyi +++ b/stdlib/re.pyi @@ -239,9 +239,7 @@ if sys.version_info < (3, 13): T: Final = RegexFlag.T TEMPLATE: Final = RegexFlag.TEMPLATE if sys.version_info >= (3, 11): - # pytype chokes on `NOFLAG: Final = RegexFlag.NOFLAG` with `LiteralValueError` - # mypy chokes on `NOFLAG: Final[Literal[RegexFlag.NOFLAG]]` with `Literal[...] is invalid` - NOFLAG = RegexFlag.NOFLAG + NOFLAG: Final = RegexFlag.NOFLAG _FlagsType: TypeAlias = int | RegexFlag # Type-wise the compile() overloads are unnecessary, they could also be modeled using diff --git a/stdlib/typing_extensions.pyi b/stdlib/typing_extensions.pyi index 3f7c25712..a8875450d 100644 --- a/stdlib/typing_extensions.pyi +++ b/stdlib/typing_extensions.pyi @@ -59,6 +59,7 @@ from typing import ( # noqa: Y022,Y037,Y038,Y039,UP035 TypeVar as _TypeVar, Union as Union, _Alias, + _SpecialForm, cast as cast, no_type_check as no_type_check, no_type_check_decorator as no_type_check_decorator, @@ -204,15 +205,6 @@ _TC = _TypeVar("_TC", bound=type[object]) _T_co = _TypeVar("_T_co", covariant=True) # Any type covariant containers. _T_contra = _TypeVar("_T_contra", contravariant=True) -class _Final: ... # This should be imported from typing but that breaks pytype - -# unfortunately we have to duplicate this class definition from typing.pyi or we break pytype -class _SpecialForm(_Final): - def __getitem__(self, parameters: Any) -> object: ... - if sys.version_info >= (3, 10): - def __or__(self, other: Any) -> _SpecialForm: ... - def __ror__(self, other: Any) -> _SpecialForm: ... - # Do not import (and re-export) Protocol or runtime_checkable from # typing module because type checkers need to be able to distinguish # typing.Protocol and typing_extensions.Protocol so they can properly diff --git a/stdlib/unittest/case.pyi b/stdlib/unittest/case.pyi index 89bcabf10..22d39c78f 100644 --- a/stdlib/unittest/case.pyi +++ b/stdlib/unittest/case.pyi @@ -2,18 +2,16 @@ import logging import sys import unittest.result from _typeshed import SupportsDunderGE, SupportsDunderGT, SupportsDunderLE, SupportsDunderLT, SupportsRSub, SupportsSub +from builtins import _ClassInfo from collections.abc import Callable, Container, Iterable, Mapping, Sequence, Set as AbstractSet from contextlib import AbstractContextManager from re import Pattern from types import GenericAlias, TracebackType from typing import Any, AnyStr, Final, Generic, NoReturn, Protocol, SupportsAbs, SupportsRound, TypeVar, overload -from typing_extensions import Never, ParamSpec, Self, TypeAlias +from typing_extensions import Never, ParamSpec, Self from unittest._log import _AssertLogsContext, _LoggingWatcher from warnings import WarningMessage -if sys.version_info >= (3, 10): - from types import UnionType - _T = TypeVar("_T") _S = TypeVar("_S", bound=SupportsSub[Any, Any]) _E = TypeVar("_E", bound=BaseException) @@ -60,14 +58,6 @@ class SkipTest(Exception): class _SupportsAbsAndDunderGE(SupportsDunderGE[Any], SupportsAbs[Any], Protocol): ... -# Keep this alias in sync with builtins._ClassInfo -# We can't import it from builtins or pytype crashes, -# due to the fact that pytype uses a custom builtins stub rather than typeshed's builtins stub -if sys.version_info >= (3, 10): - _ClassInfo: TypeAlias = type | UnionType | tuple[_ClassInfo, ...] -else: - _ClassInfo: TypeAlias = type | tuple[_ClassInfo, ...] - class TestCase: failureException: type[BaseException] longMessage: bool