From 7ed7844a95310a0b390036b1298f712ce41439d3 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 16:57:17 +0000 Subject: [PATCH 01/18] Add `contextlib._GeneratorContextManagerBase` --- stdlib/contextlib.pyi | 45 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index fe72d6dd42d9..942dee3fe74b 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -5,9 +5,11 @@ from typing import ( IO, Any, AsyncIterator, + AsyncGenerator, Awaitable, Callable, ContextManager, + Generator, Generic, Iterator, Optional, @@ -24,11 +26,14 @@ if sys.version_info >= (3, 7): AbstractAsyncContextManager = AsyncContextManager +_G = TypeVar("_G", bound=Generator[Any, Any, Any] | AsyncGenerator[Any, Any]) _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) +_T_contra = TypeVar("_T_contra", contravariant=True) _T_io = TypeVar("_T_io", bound=Optional[IO[str]]) _F = TypeVar("_F", bound=Callable[..., Any]) _P = ParamSpec("_P") +_V = TypeVar("_V", covariant=True) _ExitFunc = Callable[[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]], bool] _CM_EF = TypeVar("_CM_EF", AbstractContextManager[Any], _ExitFunc) @@ -36,22 +41,44 @@ _CM_EF = TypeVar("_CM_EF", AbstractContextManager[Any], _ExitFunc) class ContextDecorator: def __call__(self, func: _F) -> _F: ... -class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator): ... - -# type ignore to deal with incomplete ParamSpec support in mypy -def contextmanager(func: Callable[_P, Iterator[_T]]) -> Callable[_P, _GeneratorContextManager[_T]]: ... # type: ignore[misc] +if sys.version_info >= (3, 7): + class _GeneratorContextManagerBase(Generic[_P, _G]): + def __init__(self, func: Callable[_P, _G], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: _G + func: Callable[_P, _G] + args: _P.args # type: ignore[name-defined] + kwds: _P.kwds # type: ignore[name-defined] + class _GeneratorContextManager( + _GeneratorContextManagerBase[_P, Generator[_T_co, _T_contra, _V]], # type: ignore[misc] + AbstractContextManager[_T_co], + ContextDecorator, + Generic[_P, _T_co, _T_contra, _V], + ): ... + def contextmanager( + func: Callable[_P, Generator[_T_co, _T_contra, _V]] + ) -> Callable[_P, _GeneratorContextManager[_P, _T_co, _T_contra, _V]]: ... + +else: + class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): ... + def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... if sys.version_info >= (3, 10): _AF = TypeVar("_AF", bound=Callable[..., Awaitable[Any]]) class AsyncContextDecorator: def __call__(self, func: _AF) -> _AF: ... - class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], AsyncContextDecorator): ... + class _AsyncGeneratorContextManager( + _GeneratorContextManagerBase[_P, AsyncGenerator[_T_co, _T_contra]], # type: ignore[misc] + AbstractAsyncContextManager[_T_co], + AsyncContextDecorator, + Generic[_P, _T_co, _T_contra], + ): ... + def asynccontextmanager( + func: Callable[_P, AsyncGenerator[_T_co, _T_contra]] + ) -> Callable[_P, _AsyncGeneratorContextManager[_P, _T_co, _T_contra]]: ... elif sys.version_info >= (3, 7): - class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co]): ... - -if sys.version_info >= (3, 7): - def asynccontextmanager(func: Callable[_P, AsyncIterator[_T]]) -> Callable[_P, _AsyncGeneratorContextManager[_T]]: ... # type: ignore[misc] + class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): ... + def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... class _SupportsClose(Protocol): def close(self) -> object: ... From dd4b78bb815b69ba859cda2ed3abbdd9898f361a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Dec 2021 17:00:48 +0000 Subject: [PATCH 02/18] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/contextlib.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 942dee3fe74b..e6bbb78faef9 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -4,8 +4,8 @@ from types import TracebackType from typing import ( IO, Any, - AsyncIterator, AsyncGenerator, + AsyncIterator, Awaitable, Callable, ContextManager, From 81646129841f4db4ea0798fd1a1b989b1ac2ff4e Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:08:55 +0000 Subject: [PATCH 03/18] Fix `decorator` --- stubs/decorator/decorator.pyi | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index 0d50a5412a1d..cce6d870ffba 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -1,8 +1,12 @@ import sys -from typing import Any, Callable, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar +from typing import Any, Callable, Generic, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar +from typing_extensions import ParamSpec -_C = TypeVar("_C", bound=Callable[..., Any]) _Func = TypeVar("_Func", bound=Callable[..., Any]) +_P = ParamSpec("_P") +_T_co = TypeVar("_T_co", covariant=True) +_T_contra = TypeVar("_T_contra", contravariant=True) +_V = TypeVar("_V", covariant=True) _T = TypeVar("_T") def get_init(cls: type) -> None: ... @@ -76,8 +80,10 @@ def decorator( caller: Callable[..., Any], _func: Callable[..., Any] | None = ... ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... -class ContextManager(_GeneratorContextManager[_T]): - def __call__(self, func: _C) -> _C: ... +if sys.version_info >= (3, 7): + class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... +else: + class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., ContextManager[_T]]: ... def dispatch_on(*dispatch_args: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... From 835335af02b4374709867f3567993b97e58ae020 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Dec 2021 17:10:17 +0000 Subject: [PATCH 04/18] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/decorator/decorator.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index cce6d870ffba..569788d08cf5 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -82,6 +82,7 @@ def decorator( if sys.version_info >= (3, 7): class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... + else: class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... From 2ddceea7216829a22b6baf5a679c5363566ed3ec Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:13:22 +0000 Subject: [PATCH 05/18] More `decorator` fixes --- stubs/decorator/decorator.pyi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index cce6d870ffba..3136cbed3749 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -82,8 +82,10 @@ def decorator( if sys.version_info >= (3, 7): class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... + def contextmanager(func: Callable[_P, Generator[_T_co, _T_contra, _V]]) -> Callable[_P, ContextManager[_P, _T_co, _T_contra, _V]]: ... else: class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... + def contextmanager(func: Callable[_P, Iterator[_T]]) -> Callable[_P, ContextManager[_T_co]]: ... + -def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., ContextManager[_T]]: ... def dispatch_on(*dispatch_args: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... From 0c59017cb6bced9bf696059b64e295e362a4b5e9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Dec 2021 17:16:27 +0000 Subject: [PATCH 06/18] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stubs/decorator/decorator.pyi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index 69cb5a21b0c2..cb6d442c6f46 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -82,11 +82,12 @@ def decorator( if sys.version_info >= (3, 7): class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... - def contextmanager(func: Callable[_P, Generator[_T_co, _T_contra, _V]]) -> Callable[_P, ContextManager[_P, _T_co, _T_contra, _V]]: ... + def contextmanager( + func: Callable[_P, Generator[_T_co, _T_contra, _V]] + ) -> Callable[_P, ContextManager[_P, _T_co, _T_contra, _V]]: ... else: class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... def contextmanager(func: Callable[_P, Iterator[_T]]) -> Callable[_P, ContextManager[_T_co]]: ... - def dispatch_on(*dispatch_args: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... From 6e09569eb75c4b75e42ac562f090b08f3f20e8bb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:19:49 +0000 Subject: [PATCH 07/18] Fix --- stubs/decorator/decorator.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index cb6d442c6f46..8bb07a043b76 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -1,5 +1,5 @@ import sys -from typing import Any, Callable, Generic, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar +from typing import Any, Callable, Generator, Generic, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar from typing_extensions import ParamSpec _Func = TypeVar("_Func", bound=Callable[..., Any]) @@ -88,6 +88,6 @@ if sys.version_info >= (3, 7): else: class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... - def contextmanager(func: Callable[_P, Iterator[_T]]) -> Callable[_P, ContextManager[_T_co]]: ... + def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, ContextManager[_T_co]]: ... def dispatch_on(*dispatch_args: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... From 49539556e7ad14955961874d31c699e33358e6ad Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:22:14 +0000 Subject: [PATCH 08/18] Add `type: ignore` for mypy --- stubs/decorator/decorator.pyi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index 8bb07a043b76..3c6649859e6f 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -81,7 +81,8 @@ def decorator( ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... if sys.version_info >= (3, 7): - class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... + # type-ignore because mypy thinks _P is unbound (it isn't) + class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... # type: ignore[misc] def contextmanager( func: Callable[_P, Generator[_T_co, _T_contra, _V]] ) -> Callable[_P, ContextManager[_P, _T_co, _T_contra, _V]]: ... From ad6d7fe254d6598ecca124c10d63c7b7778380db Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:36:52 +0000 Subject: [PATCH 09/18] Hopefully this will reduce primer diff --- stdlib/contextlib.pyi | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index e6bbb78faef9..d0803dcf0fe1 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -26,7 +26,6 @@ if sys.version_info >= (3, 7): AbstractAsyncContextManager = AsyncContextManager -_G = TypeVar("_G", bound=Generator[Any, Any, Any] | AsyncGenerator[Any, Any]) _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) _T_contra = TypeVar("_T_contra", contravariant=True) @@ -42,18 +41,21 @@ class ContextDecorator: def __call__(self, func: _F) -> _F: ... if sys.version_info >= (3, 7): - class _GeneratorContextManagerBase(Generic[_P, _G]): - def __init__(self, func: Callable[_P, _G], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] - gen: _G - func: Callable[_P, _G] + class _GeneratorContextManagerBase(Generic[_P]): + def __init__(self, func: Callable[_P, Any], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: Any + func: Callable[_P, Any] args: _P.args # type: ignore[name-defined] kwds: _P.kwds # type: ignore[name-defined] class _GeneratorContextManager( - _GeneratorContextManagerBase[_P, Generator[_T_co, _T_contra, _V]], # type: ignore[misc] + _GeneratorContextManagerBase[_P], # type: ignore[misc] AbstractContextManager[_T_co], ContextDecorator, Generic[_P, _T_co, _T_contra, _V], - ): ... + ): + def __init__(self, func: Callable[_P, Generator[_T_co, _T_contra, _V]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: Generator[_T_co, _T_contra, _V] + func: Callable[_P, Generator[_T_co, _T_contra, _V]] def contextmanager( func: Callable[_P, Generator[_T_co, _T_contra, _V]] ) -> Callable[_P, _GeneratorContextManager[_P, _T_co, _T_contra, _V]]: ... @@ -67,11 +69,14 @@ if sys.version_info >= (3, 10): class AsyncContextDecorator: def __call__(self, func: _AF) -> _AF: ... class _AsyncGeneratorContextManager( - _GeneratorContextManagerBase[_P, AsyncGenerator[_T_co, _T_contra]], # type: ignore[misc] + _GeneratorContextManagerBase[_P], # type: ignore[misc] AbstractAsyncContextManager[_T_co], AsyncContextDecorator, Generic[_P, _T_co, _T_contra], - ): ... + ): + def __init__(self, func: Callable[_P, AsyncGenerator[_T_co, _T_contra]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: AsyncGenerator[_T_co, _T_contra] + func: Callable[_P, AsyncGenerator[_T_co, _T_contra]] def asynccontextmanager( func: Callable[_P, AsyncGenerator[_T_co, _T_contra]] ) -> Callable[_P, _AsyncGeneratorContextManager[_P, _T_co, _T_contra]]: ... From 52e8874916ebcc94e60b65739f6cb00d109f7ef2 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:53:34 +0000 Subject: [PATCH 10/18] Experiment with using `Iterator` instead of `Generator` --- stdlib/contextlib.pyi | 24 +++++++++++------------- stubs/decorator/decorator.pyi | 10 +++------- 2 files changed, 14 insertions(+), 20 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index d0803dcf0fe1..42b8d019b336 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -51,14 +51,12 @@ if sys.version_info >= (3, 7): _GeneratorContextManagerBase[_P], # type: ignore[misc] AbstractContextManager[_T_co], ContextDecorator, - Generic[_P, _T_co, _T_contra, _V], + Generic[_P, _T_co], ): - def __init__(self, func: Callable[_P, Generator[_T_co, _T_contra, _V]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] - gen: Generator[_T_co, _T_contra, _V] - func: Callable[_P, Generator[_T_co, _T_contra, _V]] - def contextmanager( - func: Callable[_P, Generator[_T_co, _T_contra, _V]] - ) -> Callable[_P, _GeneratorContextManager[_P, _T_co, _T_contra, _V]]: ... + def __init__(self, func: Callable[_P, Iterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: Generator[_T_co, Any, Any] + func: Callable[_P, Generator[_T_co, Any, Any]] + def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_P, _T_co]]: ... else: class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): ... @@ -72,14 +70,14 @@ if sys.version_info >= (3, 10): _GeneratorContextManagerBase[_P], # type: ignore[misc] AbstractAsyncContextManager[_T_co], AsyncContextDecorator, - Generic[_P, _T_co, _T_contra], + Generic[_P, _T_co], ): - def __init__(self, func: Callable[_P, AsyncGenerator[_T_co, _T_contra]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] - gen: AsyncGenerator[_T_co, _T_contra] - func: Callable[_P, AsyncGenerator[_T_co, _T_contra]] + def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: AsyncGenerator[_T_co, Any] + func: Callable[_P, AsyncGenerator[_T_co, Any]] def asynccontextmanager( - func: Callable[_P, AsyncGenerator[_T_co, _T_contra]] - ) -> Callable[_P, _AsyncGeneratorContextManager[_P, _T_co, _T_contra]]: ... + func: Callable[_P, AsyncIterator[_T_co]] + ) -> Callable[_P, _AsyncGeneratorContextManager[_P, _T_co]]: ... elif sys.version_info >= (3, 7): class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): ... diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index 3c6649859e6f..f2ae8f47cf1f 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -1,12 +1,10 @@ import sys -from typing import Any, Callable, Generator, Generic, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar +from typing import Any, Callable, Generic, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar from typing_extensions import ParamSpec _Func = TypeVar("_Func", bound=Callable[..., Any]) _P = ParamSpec("_P") _T_co = TypeVar("_T_co", covariant=True) -_T_contra = TypeVar("_T_contra", contravariant=True) -_V = TypeVar("_V", covariant=True) _T = TypeVar("_T") def get_init(cls: type) -> None: ... @@ -82,10 +80,8 @@ def decorator( if sys.version_info >= (3, 7): # type-ignore because mypy thinks _P is unbound (it isn't) - class ContextManager(_GeneratorContextManager[_P, _T_co, _T_contra, _V], Generic[_P, _T_co, _T_contra, _V]): ... # type: ignore[misc] - def contextmanager( - func: Callable[_P, Generator[_T_co, _T_contra, _V]] - ) -> Callable[_P, ContextManager[_P, _T_co, _T_contra, _V]]: ... + class ContextManager(_GeneratorContextManager[_P, _T_co], Generic[_P, _T_co]): ... # type: ignore[misc] + def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, ContextManager[_P, _T_co]]: ... else: class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... From 3a8fcf9c57cc40b224f86d36dc3ef4b990fb9beb Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 17:54:50 +0000 Subject: [PATCH 11/18] Unused `TypeVar`s --- stdlib/contextlib.pyi | 2 -- 1 file changed, 2 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 42b8d019b336..77628aac19b0 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -28,11 +28,9 @@ if sys.version_info >= (3, 7): _T = TypeVar("_T") _T_co = TypeVar("_T_co", covariant=True) -_T_contra = TypeVar("_T_contra", contravariant=True) _T_io = TypeVar("_T_io", bound=Optional[IO[str]]) _F = TypeVar("_F", bound=Callable[..., Any]) _P = ParamSpec("_P") -_V = TypeVar("_V", covariant=True) _ExitFunc = Callable[[Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType]], bool] _CM_EF = TypeVar("_CM_EF", AbstractContextManager[Any], _ExitFunc) From 8d1813b6b8db4913f5f2fbd17cc347e9957ff99a Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 18:22:03 +0000 Subject: [PATCH 12/18] Use `ParamSpec` less --- stdlib/contextlib.pyi | 30 ++++++++++-------------------- stubs/decorator/decorator.pyi | 10 ++-------- 2 files changed, 12 insertions(+), 28 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 77628aac19b0..b3ee9d5efc70 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -39,22 +39,17 @@ class ContextDecorator: def __call__(self, func: _F) -> _F: ... if sys.version_info >= (3, 7): - class _GeneratorContextManagerBase(Generic[_P]): + class _GeneratorContextManagerBase: def __init__(self, func: Callable[_P, Any], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] gen: Any - func: Callable[_P, Any] - args: _P.args # type: ignore[name-defined] - kwds: _P.kwds # type: ignore[name-defined] - class _GeneratorContextManager( - _GeneratorContextManagerBase[_P], # type: ignore[misc] - AbstractContextManager[_T_co], - ContextDecorator, - Generic[_P, _T_co], - ): + func: Callable[..., Any] + args: tuple[Any, ...] + kwds: dict[str, Any] + class _GeneratorContextManager(_GeneratorContextManagerBase, AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): def __init__(self, func: Callable[_P, Iterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] gen: Generator[_T_co, Any, Any] - func: Callable[_P, Generator[_T_co, Any, Any]] - def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_P, _T_co]]: ... + func: Callable[..., Generator[_T_co, Any, Any]] + def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... else: class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): ... @@ -65,17 +60,12 @@ if sys.version_info >= (3, 10): class AsyncContextDecorator: def __call__(self, func: _AF) -> _AF: ... class _AsyncGeneratorContextManager( - _GeneratorContextManagerBase[_P], # type: ignore[misc] - AbstractAsyncContextManager[_T_co], - AsyncContextDecorator, - Generic[_P, _T_co], + _GeneratorContextManagerBase, AbstractAsyncContextManager[_T_co], AsyncContextDecorator, Generic[_T_co] ): def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] gen: AsyncGenerator[_T_co, Any] - func: Callable[_P, AsyncGenerator[_T_co, Any]] - def asynccontextmanager( - func: Callable[_P, AsyncIterator[_T_co]] - ) -> Callable[_P, _AsyncGeneratorContextManager[_P, _T_co]]: ... + func: Callable[..., AsyncGenerator[_T_co, Any]] + def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... elif sys.version_info >= (3, 7): class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): ... diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index f2ae8f47cf1f..463ed7f7c74f 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -78,13 +78,7 @@ def decorator( caller: Callable[..., Any], _func: Callable[..., Any] | None = ... ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... -if sys.version_info >= (3, 7): - # type-ignore because mypy thinks _P is unbound (it isn't) - class ContextManager(_GeneratorContextManager[_P, _T_co], Generic[_P, _T_co]): ... # type: ignore[misc] - def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, ContextManager[_P, _T_co]]: ... - -else: - class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... - def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, ContextManager[_T_co]]: ... +class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... +def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, ContextManager[_T_co]]: ... def dispatch_on(*dispatch_args: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... From 2606822d1bf56f3df3dc96d57c7e7f8283a880bd Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 18:33:11 +0000 Subject: [PATCH 13/18] Increase type specificity in base class --- stdlib/contextlib.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index b3ee9d5efc70..61eab5a1de3a 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -40,9 +40,9 @@ class ContextDecorator: if sys.version_info >= (3, 7): class _GeneratorContextManagerBase: - def __init__(self, func: Callable[_P, Any], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] - gen: Any - func: Callable[..., Any] + def __init__(self, func: Callable[_P, Iterator[Any] | AsyncIterator[Any]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: Generator[Any, Any, Any] | AsyncGenerator[Any, Any] + func: Callable[..., Generator[Any, Any, Any] | AsyncGenerator[Any, Any]] args: tuple[Any, ...] kwds: dict[str, Any] class _GeneratorContextManager(_GeneratorContextManagerBase, AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): From d1b4ace3621083956cd9d5fe96243333e9a43941 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 18:44:56 +0000 Subject: [PATCH 14/18] Revert changes to `decorator` (irrelevant now that the number of parameters for `_GeneratorContextManager` has not changed, should be done in a separate PR) --- stubs/decorator/decorator.pyi | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/stubs/decorator/decorator.pyi b/stubs/decorator/decorator.pyi index 463ed7f7c74f..0d50a5412a1d 100644 --- a/stubs/decorator/decorator.pyi +++ b/stubs/decorator/decorator.pyi @@ -1,10 +1,8 @@ import sys -from typing import Any, Callable, Generic, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar -from typing_extensions import ParamSpec +from typing import Any, Callable, Iterator, NamedTuple, Pattern, Text, Tuple, TypeVar +_C = TypeVar("_C", bound=Callable[..., Any]) _Func = TypeVar("_Func", bound=Callable[..., Any]) -_P = ParamSpec("_P") -_T_co = TypeVar("_T_co", covariant=True) _T = TypeVar("_T") def get_init(cls: type) -> None: ... @@ -78,7 +76,8 @@ def decorator( caller: Callable[..., Any], _func: Callable[..., Any] | None = ... ) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... -class ContextManager(_GeneratorContextManager[_T_co], Generic[_T_co]): ... +class ContextManager(_GeneratorContextManager[_T]): + def __call__(self, func: _C) -> _C: ... -def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, ContextManager[_T_co]]: ... +def contextmanager(func: Callable[..., Iterator[_T]]) -> Callable[..., ContextManager[_T]]: ... def dispatch_on(*dispatch_args: Any) -> Callable[[Callable[..., Any]], Callable[..., Any]]: ... From 7d0db92a967869cd6dc16d824eb259046cff1a98 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 18:52:20 +0000 Subject: [PATCH 15/18] Simplify version guards --- stdlib/contextlib.pyi | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 61eab5a1de3a..51243b475504 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -49,11 +49,11 @@ if sys.version_info >= (3, 7): def __init__(self, func: Callable[_P, Iterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] gen: Generator[_T_co, Any, Any] func: Callable[..., Generator[_T_co, Any, Any]] - def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... else: class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): ... - def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... + +def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... if sys.version_info >= (3, 10): _AF = TypeVar("_AF", bound=Callable[..., Awaitable[Any]]) @@ -65,10 +65,11 @@ if sys.version_info >= (3, 10): def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] gen: AsyncGenerator[_T_co, Any] func: Callable[..., AsyncGenerator[_T_co, Any]] - def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... elif sys.version_info >= (3, 7): class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): ... + +if sys.version_info >= (3, 7): def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... class _SupportsClose(Protocol): From b2cdc57feb5107db505c17425bfa0609285b0f05 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 19:11:07 +0000 Subject: [PATCH 16/18] Remove `_GeneratorContextManagerBase` --- stdlib/contextlib.pyi | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 51243b475504..351561df4433 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -38,20 +38,15 @@ _CM_EF = TypeVar("_CM_EF", AbstractContextManager[Any], _ExitFunc) class ContextDecorator: def __call__(self, func: _F) -> _F: ... -if sys.version_info >= (3, 7): - class _GeneratorContextManagerBase: - def __init__(self, func: Callable[_P, Iterator[Any] | AsyncIterator[Any]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] - gen: Generator[Any, Any, Any] | AsyncGenerator[Any, Any] - func: Callable[..., Generator[Any, Any, Any] | AsyncGenerator[Any, Any]] - args: tuple[Any, ...] - kwds: dict[str, Any] - class _GeneratorContextManager(_GeneratorContextManagerBase, AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): - def __init__(self, func: Callable[_P, Iterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] - gen: Generator[_T_co, Any, Any] - func: Callable[..., Generator[_T_co, Any, Any]] - -else: - class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): ... +class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, Generic[_T_co]): + # In Python <= 3.6, __init__ and all instance attributes are defined directly on this class. + # In Python >= 3.7, __init__ and all instance attributes are inherited from _GeneratorContextManagerBase + # _GeneratorContextManagerBase is more trouble than it's worth to include in the stub; see #6676 + def __init__(self, func: Callable[_P, Iterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: Generator[_T_co, Any, Any] + func: Callable[..., Generator[_T_co, Any, Any]] + args: tuple[Any, ...] + kwds: dict[str, Any] def contextmanager(func: Callable[_P, Iterator[_T_co]]) -> Callable[_P, _GeneratorContextManager[_T_co]]: ... @@ -59,15 +54,22 @@ if sys.version_info >= (3, 10): _AF = TypeVar("_AF", bound=Callable[..., Awaitable[Any]]) class AsyncContextDecorator: def __call__(self, func: _AF) -> _AF: ... - class _AsyncGeneratorContextManager( - _GeneratorContextManagerBase, AbstractAsyncContextManager[_T_co], AsyncContextDecorator, Generic[_T_co] - ): + class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], AsyncContextDecorator, Generic[_T_co]): + # __init__ and these attributes are actually defined in the base class _GeneratorContextManagerBase, + # which is more trouble than it's worth to include in the stub (see #6676) def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] gen: AsyncGenerator[_T_co, Any] func: Callable[..., AsyncGenerator[_T_co, Any]] + args: tuple[Any, ...] + kwds: dict[str, Any] elif sys.version_info >= (3, 7): - class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): ... + class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): + def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + gen: AsyncGenerator[_T_co, Any] + func: Callable[..., AsyncGenerator[_T_co, Any]] + args: tuple[Any, ...] + kwds: dict[str, Any] if sys.version_info >= (3, 7): def asynccontextmanager(func: Callable[_P, AsyncIterator[_T_co]]) -> Callable[_P, _AsyncGeneratorContextManager[_T_co]]: ... From f21ad01c8037ced47ef24aff18d711641c854e75 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Thu, 23 Dec 2021 19:13:52 +0000 Subject: [PATCH 17/18] Remove unused allowlist entry --- tests/stubtest_allowlists/py36.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/stubtest_allowlists/py36.txt b/tests/stubtest_allowlists/py36.txt index 56c9d12faa2b..790cad697627 100644 --- a/tests/stubtest_allowlists/py36.txt +++ b/tests/stubtest_allowlists/py36.txt @@ -20,7 +20,6 @@ collections.AsyncGenerator.ag_frame collections.AsyncGenerator.ag_running collections.Callable collections.UserString.maketrans -contextlib._GeneratorContextManager.__init__ datetime.datetime_CAPI distutils.cygwinccompiler.RE_VERSION distutils.dist.command_re From d652c29cdc1c85993c7678757fcaa8935bc00775 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Sun, 26 Dec 2021 09:31:51 +0000 Subject: [PATCH 18/18] Remove use of ParamSpec, for now --- stdlib/contextlib.pyi | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/stdlib/contextlib.pyi b/stdlib/contextlib.pyi index 351561df4433..b536c36678a2 100644 --- a/stdlib/contextlib.pyi +++ b/stdlib/contextlib.pyi @@ -42,7 +42,7 @@ class _GeneratorContextManager(AbstractContextManager[_T_co], ContextDecorator, # In Python <= 3.6, __init__ and all instance attributes are defined directly on this class. # In Python >= 3.7, __init__ and all instance attributes are inherited from _GeneratorContextManagerBase # _GeneratorContextManagerBase is more trouble than it's worth to include in the stub; see #6676 - def __init__(self, func: Callable[_P, Iterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + def __init__(self, func: Callable[..., Iterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... gen: Generator[_T_co, Any, Any] func: Callable[..., Generator[_T_co, Any, Any]] args: tuple[Any, ...] @@ -57,7 +57,7 @@ if sys.version_info >= (3, 10): class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], AsyncContextDecorator, Generic[_T_co]): # __init__ and these attributes are actually defined in the base class _GeneratorContextManagerBase, # which is more trouble than it's worth to include in the stub (see #6676) - def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + def __init__(self, func: Callable[..., AsyncIterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... gen: AsyncGenerator[_T_co, Any] func: Callable[..., AsyncGenerator[_T_co, Any]] args: tuple[Any, ...] @@ -65,7 +65,7 @@ if sys.version_info >= (3, 10): elif sys.version_info >= (3, 7): class _AsyncGeneratorContextManager(AbstractAsyncContextManager[_T_co], Generic[_T_co]): - def __init__(self, func: Callable[_P, AsyncIterator[_T_co]], args: _P.args, kwds: _P.kwds) -> None: ... # type: ignore[name-defined] + def __init__(self, func: Callable[..., AsyncIterator[_T_co]], args: tuple[Any, ...], kwds: dict[str, Any]) -> None: ... gen: AsyncGenerator[_T_co, Any] func: Callable[..., AsyncGenerator[_T_co, Any]] args: tuple[Any, ...]