From ea7bbbdad7abf05a3bd3feb25eef93b53165e2d9 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 31 Jul 2022 14:27:47 +0100 Subject: [PATCH] Move `Match` and `Pattern` to `re.pyi`; move `ContextManager` protocols to `contextlib.pyi` (#8447) --- stdlib/contextlib.pyi | 20 +++++- stdlib/re.pyi | 124 ++++++++++++++++++++++++++++++++++++- stdlib/typing.pyi | 141 +++--------------------------------------- 3 files changed, 145 insertions(+), 140 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index dde87c041..83f1cbf08 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -1,8 +1,9 @@ import sys from _typeshed import Self, StrOrBytesPath +from abc import abstractmethod from collections.abc import AsyncGenerator, AsyncIterator, Awaitable, Callable, Generator, Iterator from types import TracebackType -from typing import IO, Any, AsyncContextManager, ContextManager, Generic, Protocol, TypeVar, overload # noqa: Y022,Y027 +from typing import IO, Any, Generic, Protocol, TypeVar, overload, runtime_checkable from typing_extensions import ParamSpec, TypeAlias __all__ = [ @@ -35,8 +36,21 @@ _P = ParamSpec("_P") _ExitFunc: TypeAlias = Callable[[type[BaseException] | None, BaseException | None, TracebackType | None], bool | None] _CM_EF = TypeVar("_CM_EF", bound=AbstractContextManager[Any] | _ExitFunc) -AbstractContextManager = ContextManager -AbstractAsyncContextManager = AsyncContextManager +@runtime_checkable +class AbstractContextManager(Protocol[_T_co]): + def __enter__(self) -> _T_co: ... + @abstractmethod + def __exit__( + self, __exc_type: type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None + ) -> bool | None: ... + +@runtime_checkable +class AbstractAsyncContextManager(Protocol[_T_co]): + async def __aenter__(self) -> _T_co: ... + @abstractmethod + async def __aexit__( + self, __exc_type: type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None + ) -> bool | None: ... class ContextDecorator: def __call__(self, func: _F) -> _F: ... diff --git a/stdlib/re.pyi b/stdlib/re.pyi index 17b2ec011..3e52d209e 100644 --- a/stdlib/re.pyi +++ b/stdlib/re.pyi @@ -2,10 +2,13 @@ import enum import sre_compile import sys from _typeshed import ReadableBuffer -from collections.abc import Callable, Iterator +from collections.abc import Callable, Iterator, Mapping from sre_constants import error as error -from typing import Any, AnyStr, Match as Match, Pattern as Pattern, overload -from typing_extensions import TypeAlias +from typing import Any, AnyStr, Generic, TypeVar, overload +from typing_extensions import Literal, TypeAlias, final + +if sys.version_info >= (3, 9): + from types import GenericAlias __all__ = [ "match", @@ -42,6 +45,121 @@ __all__ = [ if sys.version_info >= (3, 11): __all__ += ["NOFLAG", "RegexFlag"] +_T = TypeVar("_T") + +@final +class Match(Generic[AnyStr]): + @property + def pos(self) -> int: ... + @property + def endpos(self) -> int: ... + @property + def lastindex(self) -> int | None: ... + @property + def lastgroup(self) -> str | None: ... + @property + def string(self) -> AnyStr: ... + + # The regular expression object whose match() or search() method produced + # this match instance. + @property + def re(self) -> Pattern[AnyStr]: ... + @overload + def expand(self: Match[str], template: str) -> str: ... + @overload + def expand(self: Match[bytes], template: ReadableBuffer) -> bytes: ... + # group() returns "AnyStr" or "AnyStr | None", depending on the pattern. + @overload + def group(self, __group: Literal[0] = ...) -> AnyStr: ... + @overload + def group(self, __group: str | int) -> AnyStr | Any: ... + @overload + def group(self, __group1: str | int, __group2: str | int, *groups: str | int) -> tuple[AnyStr | Any, ...]: ... + # Each item of groups()'s return tuple is either "AnyStr" or + # "AnyStr | None", depending on the pattern. + @overload + def groups(self) -> tuple[AnyStr | Any, ...]: ... + @overload + def groups(self, default: _T) -> tuple[AnyStr | _T, ...]: ... + # Each value in groupdict()'s return dict is either "AnyStr" or + # "AnyStr | None", depending on the pattern. + @overload + def groupdict(self) -> dict[str, AnyStr | Any]: ... + @overload + def groupdict(self, default: _T) -> dict[str, AnyStr | _T]: ... + def start(self, __group: int | str = ...) -> int: ... + def end(self, __group: int | str = ...) -> int: ... + def span(self, __group: int | str = ...) -> tuple[int, int]: ... + @property + def regs(self) -> tuple[tuple[int, int], ...]: ... # undocumented + # __getitem__() returns "AnyStr" or "AnyStr | None", depending on the pattern. + @overload + def __getitem__(self, __key: Literal[0]) -> AnyStr: ... + @overload + def __getitem__(self, __key: int | str) -> AnyStr | Any: ... + def __copy__(self) -> Match[AnyStr]: ... + def __deepcopy__(self, __memo: Any) -> Match[AnyStr]: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any) -> GenericAlias: ... + +@final +class Pattern(Generic[AnyStr]): + @property + def flags(self) -> int: ... + @property + def groupindex(self) -> Mapping[str, int]: ... + @property + def groups(self) -> int: ... + @property + def pattern(self) -> AnyStr: ... + @overload + def search(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Match[str] | None: ... + @overload + def search(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Match[bytes] | None: ... + @overload + def match(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Match[str] | None: ... + @overload + def match(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Match[bytes] | None: ... + @overload + def fullmatch(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Match[str] | None: ... + @overload + def fullmatch(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Match[bytes] | None: ... + @overload + def split(self: Pattern[str], string: str, maxsplit: int = ...) -> list[str | Any]: ... + @overload + def split(self: Pattern[bytes], string: ReadableBuffer, maxsplit: int = ...) -> list[bytes | Any]: ... + # return type depends on the number of groups in the pattern + @overload + def findall(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> list[Any]: ... + @overload + def findall(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> list[Any]: ... + @overload + def finditer(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Iterator[Match[str]]: ... + @overload + def finditer(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Iterator[Match[bytes]]: ... + @overload + def sub(self: Pattern[str], repl: str | Callable[[Match[str]], str], string: str, count: int = ...) -> str: ... + @overload + def sub( + self: Pattern[bytes], + repl: ReadableBuffer | Callable[[Match[bytes]], ReadableBuffer], + string: ReadableBuffer, + count: int = ..., + ) -> bytes: ... + @overload + def subn(self: Pattern[str], repl: str | Callable[[Match[str]], str], string: str, count: int = ...) -> tuple[str, int]: ... + @overload + def subn( + self: Pattern[bytes], + repl: ReadableBuffer | Callable[[Match[bytes]], ReadableBuffer], + string: ReadableBuffer, + count: int = ..., + ) -> tuple[bytes, int]: ... + def __copy__(self) -> Pattern[AnyStr]: ... + def __deepcopy__(self, __memo: Any) -> Pattern[AnyStr]: ... + if sys.version_info >= (3, 9): + def __class_getitem__(cls, item: Any) -> GenericAlias: ... + # ----- re variables and constants ----- class RegexFlag(enum.IntFlag): diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 980505271..2bb840b64 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -1,7 +1,9 @@ import collections # Needed by aliases like DefaultDict, see mypy issue 2986 import sys -from _typeshed import IdentityFunction, Incomplete, ReadableBuffer, Self as TypeshedSelf, SupportsKeysAndGetItem +from _typeshed import IdentityFunction, Incomplete, Self as TypeshedSelf, SupportsKeysAndGetItem from abc import ABCMeta, abstractmethod +from contextlib import AbstractAsyncContextManager, AbstractContextManager +from re import Match as Match, Pattern as Pattern from types import ( BuiltinFunctionType, CodeType, @@ -14,10 +16,7 @@ from types import ( TracebackType, WrapperDescriptorType, ) -from typing_extensions import Literal as _Literal, ParamSpec as _ParamSpec, final as _final - -if sys.version_info >= (3, 9): - from types import GenericAlias +from typing_extensions import ParamSpec as _ParamSpec, final as _final __all__ = [ "AbstractSet", @@ -120,6 +119,9 @@ if sys.version_info >= (3, 11): "reveal_type", ] +ContextManager = AbstractContextManager +AsyncContextManager = AbstractAsyncContextManager + # This itself is only available during type checking def type_check_only(func_or_cls: _F) -> _F: ... @@ -568,22 +570,6 @@ class ValuesView(MappingView, Iterable[_VT_co], Generic[_VT_co]): if sys.version_info >= (3, 8): def __reversed__(self) -> Iterator[_VT_co]: ... -@runtime_checkable -class ContextManager(Protocol[_T_co]): - def __enter__(self) -> _T_co: ... - @abstractmethod - def __exit__( - self, __exc_type: Type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None - ) -> bool | None: ... - -@runtime_checkable -class AsyncContextManager(Protocol[_T_co]): - async def __aenter__(self) -> _T_co: ... - @abstractmethod - async def __aexit__( - self, __exc_type: Type[BaseException] | None, __exc_value: BaseException | None, __traceback: TracebackType | None - ) -> bool | None: ... - class Mapping(Collection[_KT], Generic[_KT, _VT_co]): # TODO: We wish the key type could also be covariant, but that doesn't work, # see discussion in https://github.com/python/typing/pull/273. @@ -718,119 +704,6 @@ class TextIO(IO[str]): class ByteString(Sequence[int], metaclass=ABCMeta): ... -@_final -class Match(Generic[AnyStr]): - @property - def pos(self) -> int: ... - @property - def endpos(self) -> int: ... - @property - def lastindex(self) -> int | None: ... - @property - def lastgroup(self) -> str | None: ... - @property - def string(self) -> AnyStr: ... - - # The regular expression object whose match() or search() method produced - # this match instance. - @property - def re(self) -> Pattern[AnyStr]: ... - @overload - def expand(self: Match[str], template: str) -> str: ... - @overload - def expand(self: Match[bytes], template: ReadableBuffer) -> bytes: ... - # group() returns "AnyStr" or "AnyStr | None", depending on the pattern. - @overload - def group(self, __group: _Literal[0] = ...) -> AnyStr: ... - @overload - def group(self, __group: str | int) -> AnyStr | Any: ... - @overload - def group(self, __group1: str | int, __group2: str | int, *groups: str | int) -> tuple[AnyStr | Any, ...]: ... - # Each item of groups()'s return tuple is either "AnyStr" or - # "AnyStr | None", depending on the pattern. - @overload - def groups(self) -> tuple[AnyStr | Any, ...]: ... - @overload - def groups(self, default: _T) -> tuple[AnyStr | _T, ...]: ... - # Each value in groupdict()'s return dict is either "AnyStr" or - # "AnyStr | None", depending on the pattern. - @overload - def groupdict(self) -> dict[str, AnyStr | Any]: ... - @overload - def groupdict(self, default: _T) -> dict[str, AnyStr | _T]: ... - def start(self, __group: int | str = ...) -> int: ... - def end(self, __group: int | str = ...) -> int: ... - def span(self, __group: int | str = ...) -> tuple[int, int]: ... - @property - def regs(self) -> tuple[tuple[int, int], ...]: ... # undocumented - # __getitem__() returns "AnyStr" or "AnyStr | None", depending on the pattern. - @overload - def __getitem__(self, __key: _Literal[0]) -> AnyStr: ... - @overload - def __getitem__(self, __key: int | str) -> AnyStr | Any: ... - def __copy__(self) -> Match[AnyStr]: ... - def __deepcopy__(self, __memo: Any) -> Match[AnyStr]: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... - -@_final -class Pattern(Generic[AnyStr]): - @property - def flags(self) -> int: ... - @property - def groupindex(self) -> Mapping[str, int]: ... - @property - def groups(self) -> int: ... - @property - def pattern(self) -> AnyStr: ... - @overload - def search(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Match[str] | None: ... - @overload - def search(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Match[bytes] | None: ... - @overload - def match(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Match[str] | None: ... - @overload - def match(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Match[bytes] | None: ... - @overload - def fullmatch(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Match[str] | None: ... - @overload - def fullmatch(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Match[bytes] | None: ... - @overload - def split(self: Pattern[str], string: str, maxsplit: int = ...) -> list[str | Any]: ... - @overload - def split(self: Pattern[bytes], string: ReadableBuffer, maxsplit: int = ...) -> list[bytes | Any]: ... - # return type depends on the number of groups in the pattern - @overload - def findall(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> list[Any]: ... - @overload - def findall(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> list[Any]: ... - @overload - def finditer(self: Pattern[str], string: str, pos: int = ..., endpos: int = ...) -> Iterator[Match[str]]: ... - @overload - def finditer(self: Pattern[bytes], string: ReadableBuffer, pos: int = ..., endpos: int = ...) -> Iterator[Match[bytes]]: ... - @overload - def sub(self: Pattern[str], repl: str | Callable[[Match[str]], str], string: str, count: int = ...) -> str: ... - @overload - def sub( - self: Pattern[bytes], - repl: ReadableBuffer | Callable[[Match[bytes]], ReadableBuffer], - string: ReadableBuffer, - count: int = ..., - ) -> bytes: ... - @overload - def subn(self: Pattern[str], repl: str | Callable[[Match[str]], str], string: str, count: int = ...) -> tuple[str, int]: ... - @overload - def subn( - self: Pattern[bytes], - repl: ReadableBuffer | Callable[[Match[bytes]], ReadableBuffer], - string: ReadableBuffer, - count: int = ..., - ) -> tuple[bytes, int]: ... - def __copy__(self) -> Pattern[AnyStr]: ... - def __deepcopy__(self, __memo: Any) -> Pattern[AnyStr]: ... - if sys.version_info >= (3, 9): - def __class_getitem__(cls, item: Any) -> GenericAlias: ... - # Functions _get_type_hints_obj_allowed_types = ( # noqa: Y026 # TODO: Use TypeAlias once mypy bugs are fixed