From 8866ad0042ce8f5b28c00a65af2601d16b574edf Mon Sep 17 00:00:00 2001 From: Itai Steinherz Date: Fri, 4 Mar 2022 00:22:23 +0200 Subject: [PATCH 1/8] Add missing typings to `unittest.mock` --- stdlib/unittest/mock.pyi | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index 7b14b0f78250..2f4e187145a7 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -428,14 +428,14 @@ if sys.version_info >= (3, 8): class AsyncMock(AsyncMockMixin, AsyncMagicMixin, Mock): ... # type: ignore # argument disparities between base classes class MagicProxy: - name: Any + name: str parent: Any - def __init__(self, name, parent) -> None: ... + def __init__(self, name: str, parent: Any) -> None: ... if sys.version_info < (3, 8): def __call__(self, *args: Any, **kwargs: Any) -> Any: ... - def create_mock(self): ... - def __get__(self, obj, _type: Any | None = ...): ... + def create_mock(self) -> Any: ... + def __get__(self, obj: Any, _type: Any | None = ...) -> Any: ... class _ANY: def __eq__(self, other: object) -> Literal[True]: ... From 8392dbc5dc23d159007e72068b8b39183aedefee Mon Sep 17 00:00:00 2001 From: Itai Steinherz Date: Fri, 4 Mar 2022 00:34:11 +0200 Subject: [PATCH 2/8] Strictly typecheck `unittest.mock` with pyright --- pyrightconfig.stricter.json | 1 - 1 file changed, 1 deletion(-) diff --git a/pyrightconfig.stricter.json b/pyrightconfig.stricter.json index b19bffc4cc47..d4eb2899be82 100644 --- a/pyrightconfig.stricter.json +++ b/pyrightconfig.stricter.json @@ -13,7 +13,6 @@ "stdlib/sqlite3/dbapi2.pyi", "stdlib/_tkinter.pyi", "stdlib/tkinter", - "stdlib/unittest/mock.pyi", "stdlib/xml/dom/NodeFilter.pyi", "stdlib/xml/dom/expatbuilder.pyi", "stdlib/xml/dom/minidom.pyi", From 6be90f818491f4de1b27f7e7433f87e4952c9a64 Mon Sep 17 00:00:00 2001 From: Itai Steinherz Date: Fri, 4 Mar 2022 01:15:51 +0200 Subject: [PATCH 3/8] Overhaul `_Call.__new__` typings and add missing typings --- stdlib/unittest/mock.pyi | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index 2f4e187145a7..3eb7a8ff6e8a 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import Self -from typing import Any, Awaitable, Callable, Generic, Iterable, Mapping, Sequence, TypeVar, overload +from typing import Any, Awaitable, Callable, Generic, Iterable, Mapping, Sequence, TypeVar, overload, ContextManager from typing_extensions import Literal _T = TypeVar("_T") @@ -74,21 +74,35 @@ class _Sentinel: sentinel: Any DEFAULT: Any +_ArgsKwargs = tuple[tuple[Any, ...], Mapping[str, Any]] +_NameArgsKwargs = tuple[str, tuple[Any, ...], Mapping[str, Any]] +_ValueArgument = str | tuple[Any, ...] | Mapping[str, Any] | _ArgsKwargs | _NameArgsKwargs +_CallValues = TypeVar('_CallValues', _ArgsKwargs, _NameArgsKwargs) -class _Call(tuple[Any, ...]): +class _Call(Generic[_CallValues]): + @overload def __new__( cls: type[Self], - value: Any = ..., - name: Any | None = ..., + value: _ValueArgument = ..., + name: str | None = ..., + parent: Any | None = ..., + two: Literal[True] = ..., + from_kall: bool = ..., + ) -> Self[_ArgsKwargs]: ... + @overload + def __new__( + cls: type[Self], + value: _ValueArgument = ..., + name: str | None = ..., parent: Any | None = ..., - two: bool = ..., + two: Literal[False] = ..., from_kall: bool = ..., - ) -> Self: ... + ) -> Self[_NameArgsKwargs]: ... name: Any parent: Any from_kall: Any def __init__( - self, value: Any = ..., name: Any | None = ..., parent: Any | None = ..., two: bool = ..., from_kall: bool = ... + self, value: _ValueArgument = ..., name: str | None = ..., parent: Any | None = ..., two: bool = ..., from_kall: bool = ... ) -> None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, __other: object) -> bool: ... @@ -97,9 +111,9 @@ class _Call(tuple[Any, ...]): def __getattribute__(self, attr: str) -> Any: ... if sys.version_info >= (3, 8): @property - def args(self): ... + def args(self) -> tuple[Any, ...]: ... @property - def kwargs(self): ... + def kwargs(self) -> Mapping[str, Any]: ... def call_list(self) -> Any: ... @@ -244,7 +258,7 @@ class _patch(Generic[_T]): @overload def __call__(self, func: Callable[..., _R]) -> Callable[..., _R]: ... if sys.version_info >= (3, 8): - def decoration_helper(self, patched, args, keywargs): ... + def decoration_helper(self, patched: _patch[Any], args: Sequence[Any], keywargs: Any) -> ContextManager[tuple[Sequence[Any], Any]]: ... def decorate_class(self, klass: _TT) -> _TT: ... def decorate_callable(self, func: Callable[..., _R]) -> Callable[..., _R]: ... From 1f474b5ab1b55ece5cbf3dc212d50065de1975a9 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 23:17:51 +0000 Subject: [PATCH 4/8] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/unittest/mock.pyi | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index 3eb7a8ff6e8a..eb1f657d71d5 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import Self -from typing import Any, Awaitable, Callable, Generic, Iterable, Mapping, Sequence, TypeVar, overload, ContextManager +from typing import Any, Awaitable, Callable, ContextManager, Generic, Iterable, Mapping, Sequence, TypeVar, overload from typing_extensions import Literal _T = TypeVar("_T") @@ -77,7 +77,7 @@ DEFAULT: Any _ArgsKwargs = tuple[tuple[Any, ...], Mapping[str, Any]] _NameArgsKwargs = tuple[str, tuple[Any, ...], Mapping[str, Any]] _ValueArgument = str | tuple[Any, ...] | Mapping[str, Any] | _ArgsKwargs | _NameArgsKwargs -_CallValues = TypeVar('_CallValues', _ArgsKwargs, _NameArgsKwargs) +_CallValues = TypeVar("_CallValues", _ArgsKwargs, _NameArgsKwargs) class _Call(Generic[_CallValues]): @overload @@ -102,7 +102,12 @@ class _Call(Generic[_CallValues]): parent: Any from_kall: Any def __init__( - self, value: _ValueArgument = ..., name: str | None = ..., parent: Any | None = ..., two: bool = ..., from_kall: bool = ... + self, + value: _ValueArgument = ..., + name: str | None = ..., + parent: Any | None = ..., + two: bool = ..., + from_kall: bool = ..., ) -> None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, __other: object) -> bool: ... @@ -258,7 +263,9 @@ class _patch(Generic[_T]): @overload def __call__(self, func: Callable[..., _R]) -> Callable[..., _R]: ... if sys.version_info >= (3, 8): - def decoration_helper(self, patched: _patch[Any], args: Sequence[Any], keywargs: Any) -> ContextManager[tuple[Sequence[Any], Any]]: ... + def decoration_helper( + self, patched: _patch[Any], args: Sequence[Any], keywargs: Any + ) -> ContextManager[tuple[Sequence[Any], Any]]: ... def decorate_class(self, klass: _TT) -> _TT: ... def decorate_callable(self, func: Callable[..., _R]) -> Callable[..., _R]: ... From 20ec6fab4adbc4f76439d3fdd2fda6ee77365bb5 Mon Sep 17 00:00:00 2001 From: Itai Steinherz Date: Fri, 4 Mar 2022 01:35:20 +0200 Subject: [PATCH 5/8] Make `_Call` non-generic --- stdlib/unittest/mock.pyi | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index eb1f657d71d5..e7818e45613a 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -74,30 +74,20 @@ class _Sentinel: sentinel: Any DEFAULT: Any + _ArgsKwargs = tuple[tuple[Any, ...], Mapping[str, Any]] _NameArgsKwargs = tuple[str, tuple[Any, ...], Mapping[str, Any]] _ValueArgument = str | tuple[Any, ...] | Mapping[str, Any] | _ArgsKwargs | _NameArgsKwargs -_CallValues = TypeVar("_CallValues", _ArgsKwargs, _NameArgsKwargs) -class _Call(Generic[_CallValues]): - @overload - def __new__( - cls: type[Self], - value: _ValueArgument = ..., - name: str | None = ..., - parent: Any | None = ..., - two: Literal[True] = ..., - from_kall: bool = ..., - ) -> Self[_ArgsKwargs]: ... - @overload +class _Call(tuple[Any, ...]): def __new__( cls: type[Self], value: _ValueArgument = ..., name: str | None = ..., parent: Any | None = ..., - two: Literal[False] = ..., + two: bool = ..., from_kall: bool = ..., - ) -> Self[_NameArgsKwargs]: ... + ) -> Self: ... name: Any parent: Any from_kall: Any From 03bafaa1861d882300588d59dbd6aef20bb55a13 Mon Sep 17 00:00:00 2001 From: Itai Steinherz Date: Fri, 4 Mar 2022 01:38:37 +0200 Subject: [PATCH 6/8] Fix linting --- stdlib/unittest/mock.pyi | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index e7818e45613a..70d0b114017a 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -1,6 +1,7 @@ import sys from _typeshed import Self -from typing import Any, Awaitable, Callable, ContextManager, Generic, Iterable, Mapping, Sequence, TypeVar, overload +from contextlib import AbstractContextManager +from typing import Any, Awaitable, Callable, Generic, Iterable, Mapping, Sequence, TypeVar, overload from typing_extensions import Literal _T = TypeVar("_T") @@ -255,7 +256,7 @@ class _patch(Generic[_T]): if sys.version_info >= (3, 8): def decoration_helper( self, patched: _patch[Any], args: Sequence[Any], keywargs: Any - ) -> ContextManager[tuple[Sequence[Any], Any]]: ... + ) -> AbstractContextManager[tuple[Sequence[Any], Any]]: ... def decorate_class(self, klass: _TT) -> _TT: ... def decorate_callable(self, func: Callable[..., _R]) -> Callable[..., _R]: ... From b66978efd3ab87cacf5b75a3d43f5d2a7925e4b8 Mon Sep 17 00:00:00 2001 From: Itai Steinherz Date: Fri, 4 Mar 2022 01:53:35 +0200 Subject: [PATCH 7/8] CR improvement --- stdlib/unittest/mock.pyi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index 70d0b114017a..1044e85e60d7 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -1,6 +1,6 @@ import sys from _typeshed import Self -from contextlib import AbstractContextManager +from contextlib import _GeneratorContextManager from typing import Any, Awaitable, Callable, Generic, Iterable, Mapping, Sequence, TypeVar, overload from typing_extensions import Literal @@ -78,12 +78,12 @@ DEFAULT: Any _ArgsKwargs = tuple[tuple[Any, ...], Mapping[str, Any]] _NameArgsKwargs = tuple[str, tuple[Any, ...], Mapping[str, Any]] -_ValueArgument = str | tuple[Any, ...] | Mapping[str, Any] | _ArgsKwargs | _NameArgsKwargs +_CallValue = str | tuple[Any, ...] | Mapping[str, Any] | _ArgsKwargs | _NameArgsKwargs class _Call(tuple[Any, ...]): def __new__( cls: type[Self], - value: _ValueArgument = ..., + value: _CallValue = ..., name: str | None = ..., parent: Any | None = ..., two: bool = ..., @@ -94,7 +94,7 @@ class _Call(tuple[Any, ...]): from_kall: Any def __init__( self, - value: _ValueArgument = ..., + value: _CallValue = ..., name: str | None = ..., parent: Any | None = ..., two: bool = ..., @@ -256,7 +256,7 @@ class _patch(Generic[_T]): if sys.version_info >= (3, 8): def decoration_helper( self, patched: _patch[Any], args: Sequence[Any], keywargs: Any - ) -> AbstractContextManager[tuple[Sequence[Any], Any]]: ... + ) -> _GeneratorContextManager[tuple[Sequence[Any], Any]]: ... def decorate_class(self, klass: _TT) -> _TT: ... def decorate_callable(self, func: Callable[..., _R]) -> Callable[..., _R]: ... From d1cbadbbd221311a95e173627c84e17bd04008f7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 23:54:50 +0000 Subject: [PATCH 8/8] [pre-commit.ci] auto fixes from pre-commit.com hooks --- stdlib/unittest/mock.pyi | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/stdlib/unittest/mock.pyi b/stdlib/unittest/mock.pyi index 1044e85e60d7..4f520528cd2e 100644 --- a/stdlib/unittest/mock.pyi +++ b/stdlib/unittest/mock.pyi @@ -93,12 +93,7 @@ class _Call(tuple[Any, ...]): parent: Any from_kall: Any def __init__( - self, - value: _CallValue = ..., - name: str | None = ..., - parent: Any | None = ..., - two: bool = ..., - from_kall: bool = ..., + self, value: _CallValue = ..., name: str | None = ..., parent: Any | None = ..., two: bool = ..., from_kall: bool = ... ) -> None: ... def __eq__(self, other: object) -> bool: ... def __ne__(self, __other: object) -> bool: ...