From 2170693e1182c4990eb0a9e713409cd305e64306 Mon Sep 17 00:00:00 2001 From: Alex Waygood Date: Wed, 19 Jan 2022 11:24:16 +0000 Subject: [PATCH] Add various __*or__ methods, and improve dict.__ior__ (#6961) --- stdlib/builtins.pyi | 6 +++++- stdlib/collections/__init__.pyi | 18 ++++++++++++++++++ stdlib/typing.pyi | 8 ++++++++ stdlib/weakref.pyi | 20 ++++++++++++++++++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index dcf4b6eb8..1a7eb59a3 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -869,7 +869,11 @@ class dict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): def __class_getitem__(cls, __item: Any) -> GenericAlias: ... def __or__(self, __value: Mapping[_T1, _T2]) -> dict[_KT | _T1, _VT | _T2]: ... def __ror__(self, __value: Mapping[_T1, _T2]) -> dict[_KT | _T1, _VT | _T2]: ... - def __ior__(self, __value: Mapping[_KT, _VT]) -> dict[_KT, _VT]: ... # type: ignore[misc] + # dict.__ior__ should be kept roughly in line with MutableMapping.update() + @overload # type: ignore[misc] + def __ior__(self: Self, __value: SupportsKeysAndGetItem[_KT, _VT]) -> Self: ... + @overload + def __ior__(self: Self, __value: Iterable[tuple[_KT, _VT]]) -> Self: ... class set(MutableSet[_T], Generic[_T]): def __init__(self, __iterable: Iterable[_T] = ...) -> None: ... diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index f1e14a4ce..32f996c6e 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -14,6 +14,8 @@ else: _S = TypeVar("_S") _T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") _KT = TypeVar("_KT") _VT = TypeVar("_VT") _KT_co = TypeVar("_KT_co", covariant=True) @@ -64,6 +66,14 @@ class UserDict(MutableMapping[_KT, _VT], Generic[_KT, _VT]): @classmethod @overload def fromkeys(cls, iterable: Iterable[_T], value: _S) -> UserDict[_T, _S]: ... + if sys.version_info >= (3, 9): + def __or__(self, other: UserDict[_T1, _T2] | dict[_T1, _T2]) -> UserDict[_KT | _T1, _VT | _T2]: ... + def __ror__(self, other: UserDict[_T1, _T2] | dict[_T1, _T2]) -> UserDict[_KT | _T1, _VT | _T2]: ... # type: ignore[misc] + # UserDict.__ior__ should be kept roughly in line with MutableMapping.update() + @overload # type: ignore[misc] + def __ior__(self: Self, other: SupportsKeysAndGetItem[_KT, _VT]) -> Self: ... + @overload + def __ior__(self: Self, other: Iterable[tuple[_KT, _VT]]) -> Self: ... class UserList(MutableSequence[_T]): data: list[_T] @@ -334,3 +344,11 @@ class ChainMap(MutableMapping[_KT, _VT], Generic[_KT, _VT]): @classmethod @overload def fromkeys(cls, __iterable: Iterable[_T], __value: _S) -> ChainMap[_T, _S]: ... + if sys.version_info >= (3, 9): + def __or__(self, other: Mapping[_T1, _T2]) -> ChainMap[_KT | _T1, _VT | _T2]: ... + def __ror__(self, other: Mapping[_T1, _T2]) -> ChainMap[_KT | _T1, _VT | _T2]: ... + # ChainMap.__ior__ should be kept roughly in line with MutableMapping.update() + @overload # type: ignore[misc] + def __ior__(self: Self, other: SupportsKeysAndGetItem[_KT, _VT]) -> Self: ... + @overload + def __ior__(self: Self, other: Iterable[tuple[_KT, _VT]]) -> Self: ... diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 152be0820..270b9bb56 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -481,6 +481,14 @@ class MutableMapping(Mapping[_KT, _VT], Generic[_KT, _VT]): # mypy will commit to using the first overload when the argument is # known to be a Mapping with unknown type parameters, which is closer # to the behavior we want. See mypy issue #1430. + # + # Various mapping classes have __ior__ methods that should be kept roughly in line with .update(): + # -- dict.__ior__ + # -- os._Environ.__ior__ + # -- collections.UserDict.__ior__ + # -- collections.ChainMap.__ior__ + # -- weakref.WeakValueDictionary.__ior__ + # -- weakref.WeakKeyDictionary.__ior__ @overload def update(self, __m: SupportsKeysAndGetItem[_KT, _VT], **kwargs: _VT) -> None: ... @overload diff --git a/stdlib/weakref.pyi b/stdlib/weakref.pyi index 53f5680e3..742970a60 100644 --- a/stdlib/weakref.pyi +++ b/stdlib/weakref.pyi @@ -1,3 +1,5 @@ +import sys +from _typeshed import Self, SupportsKeysAndGetItem from _weakrefset import WeakSet as WeakSet from typing import Any, Callable, Generic, Iterable, Iterator, Mapping, MutableMapping, TypeVar, overload @@ -12,6 +14,8 @@ from _weakref import ( ) _T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") _KT = TypeVar("_KT") _VT = TypeVar("_VT") _CallableT = TypeVar("_CallableT", bound=Callable[..., Any]) @@ -45,6 +49,14 @@ class WeakValueDictionary(MutableMapping[_KT, _VT]): def pop(self, key: _KT) -> _VT: ... @overload def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... + if sys.version_info >= (3, 9): + def __or__(self, other: Mapping[_T1, _T2]) -> WeakValueDictionary[_KT | _T1, _VT | _T2]: ... + def __ror__(self, other: Mapping[_T1, _T2]) -> WeakValueDictionary[_KT | _T1, _VT | _T2]: ... + # WeakValueDictionary.__ior__ should be kept roughly in line with MutableMapping.update() + @overload # type: ignore[misc] + def __ior__(self: Self, value: SupportsKeysAndGetItem[_KT, _VT]) -> Self: ... + @overload + def __ior__(self: Self, value: Iterable[tuple[_KT, _VT]]) -> Self: ... class KeyedRef(ref[_T], Generic[_KT, _T]): key: _KT @@ -74,6 +86,14 @@ class WeakKeyDictionary(MutableMapping[_KT, _VT]): def pop(self, key: _KT) -> _VT: ... @overload def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... + if sys.version_info >= (3, 9): + def __or__(self, other: Mapping[_T1, _T2]) -> WeakKeyDictionary[_KT | _T1, _VT | _T2]: ... + def __ror__(self, other: Mapping[_T1, _T2]) -> WeakKeyDictionary[_KT | _T1, _VT | _T2]: ... + # WeakKeyDictionary.__ior__ should be kept roughly in line with MutableMapping.update() + @overload # type: ignore[misc] + def __ior__(self: Self, value: SupportsKeysAndGetItem[_KT, _VT]) -> Self: ... + @overload + def __ior__(self: Self, value: Iterable[tuple[_KT, _VT]]) -> Self: ... class finalize: def __init__(self, __obj: object, __func: Callable[..., Any], *args: Any, **kwargs: Any) -> None: ...