diff --git a/stdlib/_collections_abc.pyi b/stdlib/_collections_abc.pyi index 6fc32078532e..8c2fad9fd044 100644 --- a/stdlib/_collections_abc.pyi +++ b/stdlib/_collections_abc.pyi @@ -66,7 +66,7 @@ if sys.version_info < (3, 15): if sys.version_info >= (3, 12): __all__ += ["Buffer"] -_KT_co = TypeVar("_KT_co", covariant=True) # Key type covariant containers. +_KT_co = TypeVar("_KT_co", bound=Hashable, covariant=True) # Key type covariant containers. _VT_co = TypeVar("_VT_co", covariant=True) # Value type covariant containers. @final @@ -75,7 +75,7 @@ class dict_keys(KeysView[_KT_co], Generic[_KT_co, _VT_co]): # undocumented def __reversed__(self) -> Iterator[_KT_co]: ... __hash__: ClassVar[None] # type: ignore[assignment] if sys.version_info >= (3, 13): - def isdisjoint(self, other: Iterable[_KT_co], /) -> bool: ... + def isdisjoint(self, other: Iterable[Hashable], /) -> bool: ... @property def mapping(self) -> MappingProxyType[_KT_co, _VT_co]: ... @@ -92,7 +92,7 @@ class dict_items(ItemsView[_KT_co, _VT_co]): # undocumented def __reversed__(self) -> Iterator[tuple[_KT_co, _VT_co]]: ... __hash__: ClassVar[None] # type: ignore[assignment] if sys.version_info >= (3, 13): - def isdisjoint(self, other: Iterable[tuple[_KT_co, _VT_co]], /) -> bool: ... + def isdisjoint(self, other: Iterable[Hashable], /) -> bool: ... @property def mapping(self) -> MappingProxyType[_KT_co, _VT_co]: ... diff --git a/stdlib/_decimal.pyi b/stdlib/_decimal.pyi index 75d5be277f95..4e231e8e53e5 100644 --- a/stdlib/_decimal.pyi +++ b/stdlib/_decimal.pyi @@ -58,8 +58,8 @@ if sys.version_info >= (3, 11): Emax: int | None = None, capitals: int | None = None, clamp: int | None = None, - traps: dict[_TrapType, bool] | None = None, - flags: dict[_TrapType, bool] | None = None, + traps: dict[_TrapType, bool] | None = None, # type: ignore[type-var] + flags: dict[_TrapType, bool] | None = None, # type: ignore[type-var] ) -> _ContextManager: ... else: diff --git a/stdlib/_typeshed/__init__.pyi b/stdlib/_typeshed/__init__.pyi index e74ddc687e8c..0bdcbbe3a84a 100644 --- a/stdlib/_typeshed/__init__.pyi +++ b/stdlib/_typeshed/__init__.pyi @@ -261,9 +261,13 @@ OpenBinaryMode: TypeAlias = OpenBinaryModeUpdating | OpenBinaryModeReading | Ope class HasFileno(Protocol): def fileno(self) -> int: ... +class HasFilenoAndHash(HasFileno, Protocol): + def __hash__(self) -> int: ... + FileDescriptor: TypeAlias = int # stable FileDescriptorLike: TypeAlias = int | HasFileno # stable FileDescriptorOrPath: TypeAlias = int | StrOrBytesPath +HashableFDLike: TypeAlias = int | HasFilenoAndHash # stable class SupportsRead(Protocol[_T_co]): diff --git a/stdlib/_weakrefset.pyi b/stdlib/_weakrefset.pyi index 82ffa4463f48..611ebd68be3b 100644 --- a/stdlib/_weakrefset.pyi +++ b/stdlib/_weakrefset.pyi @@ -1,4 +1,4 @@ -from collections.abc import Iterable, Iterator, MutableSet +from collections.abc import Hashable, Iterable, Iterator, MutableSet from types import GenericAlias from typing import Any, ClassVar, TypeVar, overload from typing_extensions import Self @@ -6,7 +6,7 @@ from typing_extensions import Self __all__ = ["WeakSet"] _S = TypeVar("_S") -_T = TypeVar("_T") +_T = TypeVar("_T", bound=Hashable) class WeakSet(MutableSet[_T]): @overload @@ -32,12 +32,12 @@ class WeakSet(MutableSet[_T]): def __and__(self, other: Iterable[Any]) -> Self: ... def intersection_update(self, other: Iterable[Any]) -> None: ... def __iand__(self, other: Iterable[Any]) -> Self: ... - def issubset(self, other: Iterable[_T]) -> bool: ... - def __le__(self, other: Iterable[_T]) -> bool: ... - def __lt__(self, other: Iterable[_T]) -> bool: ... - def issuperset(self, other: Iterable[_T]) -> bool: ... - def __ge__(self, other: Iterable[_T]) -> bool: ... - def __gt__(self, other: Iterable[_T]) -> bool: ... + def issubset(self, other: Iterable[Any]) -> bool: ... + def __le__(self, other: Iterable[Any]) -> bool: ... + def __lt__(self, other: Iterable[Any]) -> bool: ... + def issuperset(self, other: Iterable[Any]) -> bool: ... + def __ge__(self, other: Iterable[Any]) -> bool: ... + def __gt__(self, other: Iterable[Any]) -> bool: ... def __eq__(self, other: object) -> bool: ... def symmetric_difference(self, other: Iterable[_S]) -> WeakSet[_S | _T]: ... def __xor__(self, other: Iterable[_S]) -> WeakSet[_S | _T]: ... @@ -45,5 +45,5 @@ class WeakSet(MutableSet[_T]): def __ixor__(self, other: Iterable[_T]) -> Self: ... # type: ignore[override,misc] def union(self, other: Iterable[_S]) -> WeakSet[_S | _T]: ... def __or__(self, other: Iterable[_S]) -> WeakSet[_S | _T]: ... - def isdisjoint(self, other: Iterable[_T]) -> bool: ... + def isdisjoint(self, other: Iterable[Any]) -> bool: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 0fe6d9a69651..8a00d373fa20 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -30,7 +30,7 @@ from _typeshed import ( SupportsRichComparisonT, SupportsWrite, ) -from collections.abc import Awaitable, Callable, Iterable, Iterator, MutableSet, Reversible, Set as AbstractSet, Sized +from collections.abc import Awaitable, Callable, Hashable, Iterable, Iterator, MutableSet, Reversible, Set as AbstractSet, Sized from io import BufferedRandom, BufferedReader, BufferedWriter, FileIO, TextIOWrapper from os import PathLike from types import CellType, CodeType, EllipsisType, GenericAlias, NotImplementedType, TracebackType @@ -75,7 +75,7 @@ _I = TypeVar("_I", default=int) _T_co = TypeVar("_T_co", covariant=True) _T_contra = TypeVar("_T_contra", contravariant=True) _R_co = TypeVar("_R_co", covariant=True) -_KT = TypeVar("_KT") +_KT = TypeVar("_KT", bound=Hashable) _VT = TypeVar("_VT") _S = TypeVar("_S") _T1 = TypeVar("_T1") @@ -83,6 +83,10 @@ _T2 = TypeVar("_T2") _T3 = TypeVar("_T3") _T4 = TypeVar("_T4") _T5 = TypeVar("_T5") +_H1 = TypeVar("_H1", bound=Hashable) +_H2 = TypeVar("_H2", bound=Hashable) +_H1_co = TypeVar("_H1_co", bound=Hashable, covariant=True) + _SupportsNextT_co = TypeVar("_SupportsNextT_co", bound=SupportsNext[Any], covariant=True) _SupportsAnextT_co = TypeVar("_SupportsAnextT_co", bound=SupportsAnext[Any], covariant=True) _AwaitableT = TypeVar("_AwaitableT", bound=Awaitable[Any]) @@ -1323,10 +1327,10 @@ class dict(MutableMapping[_KT, _VT]): # See #3800 & https://github.com/python/typing/issues/548#issuecomment-683336963. @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], value: None = None, /) -> dict[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_H1], value: None = None, /) -> dict[_H1, Any | None]: ... @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], value: _S, /) -> dict[_T, _S]: ... + def fromkeys(cls, iterable: Iterable[_H1], value: _T, /) -> dict[_H1, _T]: ... # Positional-only in dict, but not in MutableMapping @overload # type: ignore[override] @@ -1353,15 +1357,15 @@ class dict(MutableMapping[_KT, _VT]): __hash__: ClassVar[None] # type: ignore[assignment] def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... if sys.version_info >= (3, 15): - def __or__(self, value: dict[_T1, _T2] | frozendict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... + def __or__(self, value: dict[_H1, _T] | frozendict[_H1, _T], /) -> dict[_KT | _H1, _VT | _T]: ... @overload - def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... + def __ror__(self, value: dict[_H1, _T], /) -> dict[_KT | _H1, _VT | _T]: ... @overload - def __ror__(self, value: frozendict[_T1, _T2], /) -> frozendict[_KT | _T1, _VT | _T2]: ... + def __ror__(self, value: frozendict[_H1, _T], /) -> frozendict[_KT | _H1, _VT | _T]: ... else: - def __or__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... - def __ror__(self, value: dict[_T1, _T2], /) -> dict[_KT | _T1, _VT | _T2]: ... + def __or__(self, value: dict[_H1, _T], /) -> dict[_KT | _H1, _VT | _T]: ... + def __ror__(self, value: dict[_H1, _T], /) -> dict[_KT | _H1, _VT | _T]: ... # dict.__ior__ should be kept roughly in line with MutableMapping.update() @overload # type: ignore[misc] @@ -1373,7 +1377,7 @@ if sys.version_info >= (3, 15): @disjoint_base class frozendict(Mapping[_KT, _VT]): @overload - def __new__(cls, /) -> frozendict[Any, Any]: ... + def __new__(cls, /) -> frozendict[Hashable, Any]: ... @overload def __new__(cls: type[frozendict[str, _VT]], /, **kwargs: _VT) -> frozendict[str, _VT]: ... @overload @@ -1394,10 +1398,10 @@ if sys.version_info >= (3, 15): @overload @classmethod - def fromkeys(cls, iterable: Iterable[_T], value: None = None, /) -> frozendict[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_H1], value: None = None, /) -> frozendict[_H1, Any | None]: ... @overload @classmethod - def fromkeys(cls, iterable: Iterable[_T], value: _S, /) -> frozendict[_T, _S]: ... + def fromkeys(cls, iterable: Iterable[_H1], value: _T, /) -> frozendict[_H1, _T]: ... @overload # type: ignore[override] def get(self, key: _KT, default: None = None, /) -> _VT | None: ... @@ -1423,72 +1427,72 @@ if sys.version_info >= (3, 15): def __ror__(self, value: frozendict[_T1, _T2], /) -> frozendict[_KT | _T1, _VT | _T2]: ... @disjoint_base -class set(MutableSet[_T]): +class set(MutableSet[_H1]): @overload def __init__(self) -> None: ... @overload - def __init__(self, iterable: Iterable[_T], /) -> None: ... - - def add(self, element: _T, /) -> None: ... - def copy(self) -> set[_T]: ... - def difference(self, *s: Iterable[object]) -> set[_T]: ... - def difference_update(self, *s: Iterable[object]) -> None: ... - def discard(self, element: object, /) -> None: ... - def intersection(self, *s: Iterable[object]) -> set[_T]: ... - def intersection_update(self, *s: Iterable[object]) -> None: ... - def isdisjoint(self, s: Iterable[object], /) -> bool: ... - def issubset(self, s: Iterable[object], /) -> bool: ... - def issuperset(self, s: Iterable[object], /) -> bool: ... - def remove(self, element: _T, /) -> None: ... - def symmetric_difference(self, s: Iterable[_S], /) -> set[_T | _S]: ... - def symmetric_difference_update(self, s: Iterable[_T], /) -> None: ... - def union(self, *s: Iterable[_S]) -> set[_T | _S]: ... - def update(self, *s: Iterable[_T]) -> None: ... + def __init__(self, iterable: Iterable[_H1], /) -> None: ... + + def add(self, element: _H1, /) -> None: ... + def copy(self) -> set[_H1]: ... + def difference(self, *s: Iterable[Hashable]) -> set[_H1]: ... + def difference_update(self, *s: Iterable[Hashable]) -> None: ... + def discard(self, element: Hashable, /) -> None: ... + def intersection(self, *s: Iterable[Hashable]) -> set[_H1]: ... + def intersection_update(self, *s: Iterable[Hashable]) -> None: ... + def isdisjoint(self, s: Iterable[Hashable], /) -> bool: ... + def issubset(self, s: Iterable[Hashable], /) -> bool: ... + def issuperset(self, s: Iterable[Hashable], /) -> bool: ... + def remove(self, element: _H1, /) -> None: ... + def symmetric_difference(self, s: Iterable[_H2], /) -> set[_H1 | _H2]: ... + def symmetric_difference_update(self, s: Iterable[_H1], /) -> None: ... + def union(self, *s: Iterable[_H2]) -> set[_H1 | _H2]: ... + def update(self, *s: Iterable[_H1]) -> None: ... def __len__(self) -> int: ... - def __contains__(self, o: object, /) -> bool: ... - def __iter__(self) -> Iterator[_T]: ... - def __and__(self, value: AbstractSet[object], /) -> set[_T]: ... - def __iand__(self, value: AbstractSet[object], /) -> Self: ... - def __or__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... - def __ior__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc] - def __sub__(self, value: AbstractSet[object], /) -> set[_T]: ... - def __isub__(self, value: AbstractSet[object], /) -> Self: ... - def __xor__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... - def __ixor__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc] - def __le__(self, value: AbstractSet[object], /) -> bool: ... - def __lt__(self, value: AbstractSet[object], /) -> bool: ... - def __ge__(self, value: AbstractSet[object], /) -> bool: ... - def __gt__(self, value: AbstractSet[object], /) -> bool: ... + def __contains__(self, o: Hashable, /) -> bool: ... + def __iter__(self) -> Iterator[_H1]: ... + def __and__(self, value: AbstractSet[Hashable], /) -> set[_H1]: ... + def __iand__(self, value: AbstractSet[Hashable], /) -> Self: ... + def __or__(self, value: AbstractSet[_H2], /) -> set[_H1 | _H2]: ... + def __ior__(self, value: AbstractSet[_H1], /) -> Self: ... # type: ignore[override,misc] + def __sub__(self, value: AbstractSet[Hashable], /) -> set[_H1]: ... + def __isub__(self, value: AbstractSet[Hashable], /) -> Self: ... + def __xor__(self, value: AbstractSet[_H2], /) -> set[_H1 | _H2]: ... + def __ixor__(self, value: AbstractSet[_H1], /) -> Self: ... # type: ignore[override,misc] + def __le__(self, value: AbstractSet[Hashable], /) -> bool: ... + def __lt__(self, value: AbstractSet[Hashable], /) -> bool: ... + def __ge__(self, value: AbstractSet[Hashable], /) -> bool: ... + def __gt__(self, value: AbstractSet[Hashable], /) -> bool: ... def __eq__(self, value: object, /) -> bool: ... __hash__: ClassVar[None] # type: ignore[assignment] def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... @disjoint_base -class frozenset(AbstractSet[_T_co]): +class frozenset(AbstractSet[_H1_co]): @overload def __new__(cls) -> Self: ... @overload - def __new__(cls, iterable: Iterable[_T_co], /) -> Self: ... + def __new__(cls, iterable: Iterable[_H1_co], /) -> Self: ... - def copy(self) -> frozenset[_T_co]: ... - def difference(self, *s: Iterable[object]) -> frozenset[_T_co]: ... - def intersection(self, *s: Iterable[object]) -> frozenset[_T_co]: ... - def isdisjoint(self, s: Iterable[object], /) -> bool: ... - def issubset(self, s: Iterable[object], /) -> bool: ... - def issuperset(self, s: Iterable[object], /) -> bool: ... - def symmetric_difference(self, s: Iterable[_S], /) -> frozenset[_T_co | _S]: ... - def union(self, *s: Iterable[_S]) -> frozenset[_T_co | _S]: ... + def copy(self) -> frozenset[_H1_co]: ... + def difference(self, *s: Iterable[Hashable]) -> frozenset[_H1_co]: ... + def intersection(self, *s: Iterable[Hashable]) -> frozenset[_H1_co]: ... + def isdisjoint(self, s: Iterable[Hashable], /) -> bool: ... + def issubset(self, s: Iterable[Hashable], /) -> bool: ... + def issuperset(self, s: Iterable[Hashable], /) -> bool: ... + def symmetric_difference(self, s: Iterable[_H1], /) -> frozenset[_H1_co | _H1]: ... + def union(self, *s: Iterable[_H1]) -> frozenset[_H1_co | _H1]: ... def __len__(self) -> int: ... - def __contains__(self, o: object, /) -> bool: ... - def __iter__(self) -> Iterator[_T_co]: ... - def __and__(self, value: AbstractSet[object], /) -> frozenset[_T_co]: ... - def __or__(self, value: AbstractSet[_S], /) -> frozenset[_T_co | _S]: ... - def __sub__(self, value: AbstractSet[object], /) -> frozenset[_T_co]: ... - def __xor__(self, value: AbstractSet[_S], /) -> frozenset[_T_co | _S]: ... - def __le__(self, value: AbstractSet[object], /) -> bool: ... - def __lt__(self, value: AbstractSet[object], /) -> bool: ... - def __ge__(self, value: AbstractSet[object], /) -> bool: ... - def __gt__(self, value: AbstractSet[object], /) -> bool: ... + def __contains__(self, o: Hashable, /) -> bool: ... + def __iter__(self) -> Iterator[_H1_co]: ... + def __and__(self, value: AbstractSet[Hashable], /) -> frozenset[_H1_co]: ... + def __or__(self, value: AbstractSet[_H1], /) -> frozenset[_H1_co | _H1]: ... + def __sub__(self, value: AbstractSet[Hashable], /) -> frozenset[_H1_co]: ... + def __xor__(self, value: AbstractSet[_H1], /) -> frozenset[_H1_co | _H1]: ... + def __le__(self, value: AbstractSet[Hashable], /) -> bool: ... + def __lt__(self, value: AbstractSet[Hashable], /) -> bool: ... + def __ge__(self, value: AbstractSet[Hashable], /) -> bool: ... + def __gt__(self, value: AbstractSet[Hashable], /) -> bool: ... def __eq__(self, value: object, /) -> bool: ... def __hash__(self) -> int: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index d9c2e342c587..e5b5e7ce7d57 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -3,6 +3,7 @@ from _collections_abc import dict_items, dict_keys, dict_values from _typeshed import SupportsItems, SupportsKeysAndGetItem, SupportsRichComparison, SupportsRichComparisonT from collections.abc import ( Callable, + Hashable, ItemsView, Iterable, Iterator, @@ -22,16 +23,14 @@ if sys.version_info >= (3, 15): __all__ = ["ChainMap", "Counter", "OrderedDict", "UserDict", "UserList", "UserString", "defaultdict", "deque", "namedtuple"] -_S = TypeVar("_S") _T = TypeVar("_T") -_T1 = TypeVar("_T1") -_T2 = TypeVar("_T2") -_KT = TypeVar("_KT") +_KT = TypeVar("_KT", bound=Hashable) _VT = TypeVar("_VT") -_KT_co = TypeVar("_KT_co", covariant=True) +_KT2 = TypeVar("_KT2") +_KT_co = TypeVar("_KT_co", bound=Hashable, covariant=True) _VT_co = TypeVar("_VT_co", covariant=True) -# namedtuple is special-cased in the type checker; the initializer is ignored. +# namedtuple is special-cased in type checkers; the initializer is ignored. def namedtuple( typename: str, field_names: str | Iterable[str], @@ -88,20 +87,20 @@ class UserDict(MutableMapping[_KT, _VT]): # See #3800 & https://github.com/python/typing/issues/548#issuecomment-683336963. @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], value: None = None) -> UserDict[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_KT], value: None = None) -> UserDict[_KT, Any | None]: ... @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], value: _S) -> UserDict[_T, _S]: ... + def fromkeys(cls, iterable: Iterable[_KT], value: _T) -> UserDict[_KT, _T]: ... @overload def __or__(self, other: UserDict[_KT, _VT] | dict[_KT, _VT]) -> Self: ... @overload - def __or__(self, other: UserDict[_T1, _T2] | dict[_T1, _T2]) -> UserDict[_KT | _T1, _VT | _T2]: ... + def __or__(self, other: UserDict[_KT2, _T] | dict[_KT2, _T]) -> UserDict[_KT | _KT2, _VT | _T]: ... @overload def __ror__(self, other: UserDict[_KT, _VT] | dict[_KT, _VT]) -> Self: ... @overload - def __ror__(self, other: UserDict[_T1, _T2] | dict[_T1, _T2]) -> UserDict[_KT | _T1, _VT | _T2]: ... + def __ror__(self, other: UserDict[_KT2, _T] | dict[_KT2, _T]) -> UserDict[_KT | _KT2, _VT | _T]: ... # UserDict.__ior__ should be kept roughly in line with MutableMapping.update() @overload # type: ignore[misc] @@ -285,67 +284,73 @@ class deque(MutableSequence[_T]): def __eq__(self, value: object, /) -> bool: ... def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... -class Counter(dict[_T, int], Generic[_T]): +class Counter(dict[_KT, int], Generic[_KT]): @overload def __init__(self, iterable: None = None, /) -> None: ... @overload def __init__(self: Counter[str], iterable: None = None, /, **kwargs: int) -> None: ... @overload - def __init__(self, mapping: SupportsKeysAndGetItem[_T, int], /) -> None: ... + def __init__(self, mapping: SupportsKeysAndGetItem[_KT, int], /) -> None: ... @overload - def __init__(self, iterable: Iterable[_T], /) -> None: ... + def __init__(self, iterable: Iterable[_KT], /) -> None: ... def copy(self) -> Self: ... - def elements(self) -> Iterator[_T]: ... - def most_common(self, n: int | None = None) -> list[tuple[_T, int]]: ... + def elements(self) -> Iterator[_KT]: ... + def most_common(self, n: int | None = None) -> list[tuple[_KT, int]]: ... @classmethod def fromkeys(cls, iterable: Any, v: int | None = None) -> NoReturn: ... # type: ignore[override] @overload def subtract(self, iterable: None = None, /) -> None: ... @overload - def subtract(self, mapping: Mapping[_T, int], /) -> None: ... + def subtract(self, mapping: Mapping[_KT, int], /) -> None: ... @overload - def subtract(self, iterable: Iterable[_T], /) -> None: ... + def subtract(self, iterable: Iterable[_KT], /) -> None: ... # Unlike dict.update(), use Mapping instead of SupportsKeysAndGetItem for the first overload # (source code does an `isinstance(other, Mapping)` check) # # The second overload is also deliberately different to dict.update() - # (if it were `Iterable[_T] | Iterable[tuple[_T, int]]`, + # (if it were `Iterable[_KT] | Iterable[tuple[_KT, int]]`, # the tuples would be added as keys, breaking type safety) @overload # type: ignore[override] - def update(self, m: Mapping[_T, int], /, **kwargs: int) -> None: ... + def update(self: Counter[str], m: Mapping[str, int], /, **kwargs: int) -> None: ... @overload - def update(self, iterable: Iterable[_T], /, **kwargs: int) -> None: ... + def update(self: Counter[str], iterable: Iterable[str], /, **kwargs: int) -> None: ... @overload - def update(self, iterable: None = None, /, **kwargs: int) -> None: ... + def update(self: Counter[str], iterable: None = None, /, **kwargs: int) -> None: ... + @overload + def update(self, m: Mapping[_KT, int], /) -> None: ... + @overload + def update(self, iterable: Iterable[_KT], /) -> None: ... + @overload + def update(self, iterable: None = None, /) -> None: ... def total(self) -> int: ... - def __missing__(self, key: _T) -> int: ... - def __delitem__(self, elem: object) -> None: ... - def __eq__(self, other: object) -> bool: ... - def __ne__(self, other: object) -> bool: ... - def __le__(self, other: Counter[Any]) -> bool: ... - def __lt__(self, other: Counter[Any]) -> bool: ... - def __ge__(self, other: Counter[Any]) -> bool: ... - def __gt__(self, other: Counter[Any]) -> bool: ... - def __add__(self, other: Counter[_S]) -> Counter[_T | _S]: ... - def __sub__(self, other: Counter[_T]) -> Counter[_T]: ... - def __and__(self, other: Counter[_T]) -> Counter[_T]: ... - def __or__(self, other: Counter[_S]) -> Counter[_T | _S]: ... # type: ignore[override] + def __missing__(self, key: _KT) -> int: ... + def __delitem__(self, elem: Hashable) -> None: ... + def __eq__(self, other: Hashable) -> bool: ... + def __ne__(self, other: Hashable) -> bool: ... + def __le__(self, other: Counter[Hashable]) -> bool: ... + def __lt__(self, other: Counter[Hashable]) -> bool: ... + def __ge__(self, other: Counter[Hashable]) -> bool: ... + def __gt__(self, other: Counter[Hashable]) -> bool: ... + def __add__(self, other: Counter[_KT2]) -> Counter[_KT | _KT2]: ... + def __sub__(self, other: Counter[_KT]) -> Counter[_KT]: ... + def __and__(self, other: Counter[_KT]) -> Counter[_KT]: ... + def __or__(self, other: Counter[_KT2]) -> Counter[_KT | _KT2]: ... # type: ignore[override] if sys.version_info >= (3, 15): - def __xor__(self, other: Counter[_S]) -> Counter[_T | _S]: ... # type: ignore[override] + def __xor__(self, other: Counter[_KT2]) -> Counter[_KT | _KT2]: ... # type: ignore[override] - def __pos__(self) -> Counter[_T]: ... - def __neg__(self) -> Counter[_T]: ... + def __pos__(self) -> Counter[_KT]: ... + def __neg__(self) -> Counter[_KT]: ... # several type: ignores because __iadd__ is supposedly incompatible with __add__, etc. - def __iadd__(self, other: SupportsItems[_T, int]) -> Self: ... # type: ignore[misc] - def __isub__(self, other: SupportsItems[_T, int]) -> Self: ... - def __iand__(self, other: SupportsItems[_T, int]) -> Self: ... - def __ior__(self, other: SupportsItems[_T, int]) -> Self: ... # type: ignore[override,misc] + def __iadd__(self, other: SupportsItems[_KT, int]) -> Self: ... # type: ignore[misc] + def __isub__(self, other: SupportsItems[_KT, int]) -> Self: ... + def __iand__(self, other: SupportsItems[_KT, int]) -> Self: ... + def __ior__(self, other: SupportsItems[_KT, int]) -> Self: ... # type: ignore[override,misc] if sys.version_info >= (3, 15): - def __ixor__(self, other: Counter[_T]) -> Self: ... # type: ignore[misc] + def __ixor__(self, other: Counter[_KT]) -> Self: ... # type: ignore[misc] # The pure-Python implementations of the "views" classes # These are exposed at runtime in `collections/__init__.py` @@ -390,12 +395,12 @@ class OrderedDict(dict[_KT, _VT]): # The signature of OrderedDict.fromkeys should be kept in line with `dict.fromkeys`, modulo positional-only differences. # Like dict.fromkeys, its true signature is not expressible in the current type system. # See #3800 & https://github.com/python/typing/issues/548#issuecomment-683336963. - @classmethod + @classmethod # type: ignore[override] @overload - def fromkeys(cls, iterable: Iterable[_T], value: None = None) -> OrderedDict[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_KT], value: None = None) -> OrderedDict[_KT, Any | None]: ... @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], value: _S) -> OrderedDict[_T, _S]: ... + def fromkeys(cls, iterable: Iterable[_KT], value: _T) -> OrderedDict[_KT, _T]: ... # Keep OrderedDict.setdefault in line with MutableMapping.setdefault, modulo positional-only differences. @overload @@ -417,24 +422,24 @@ class OrderedDict(dict[_KT, _VT]): @overload def __or__(self, value: dict[_KT, _VT] | frozendict[_KT, _VT], /) -> Self: ... @overload - def __or__(self, value: dict[_T1, _T2] | frozendict[_T1, _T2], /) -> OrderedDict[_KT | _T1, _VT | _T2]: ... + def __or__(self, value: dict[_KT2, _T] | frozendict[_KT2, _T], /) -> OrderedDict[_KT | _KT2, _VT | _T]: ... @overload # type: ignore[override] def __ror__(self, value: dict[_KT, _VT] | frozendict[_KT, _VT], /) -> Self: ... # type: ignore[override,misc] @overload def __ror__( # type: ignore[misc] - self, value: dict[_T1, _T2] | frozendict[_T1, _T2], / - ) -> OrderedDict[_KT | _T1, _VT | _T2]: ... + self, value: dict[_KT2, _T] | frozendict[_KT2, _T], / + ) -> OrderedDict[_KT | _KT2, _VT | _T]: ... else: @overload def __or__(self, value: dict[_KT, _VT], /) -> Self: ... @overload - def __or__(self, value: dict[_T1, _T2], /) -> OrderedDict[_KT | _T1, _VT | _T2]: ... + def __or__(self, value: dict[_KT2, _T], /) -> OrderedDict[_KT | _KT2, _VT | _T]: ... @overload def __ror__(self, value: dict[_KT, _VT], /) -> Self: ... @overload - def __ror__(self, value: dict[_T1, _T2], /) -> OrderedDict[_KT | _T1, _VT | _T2]: ... # type: ignore[misc] + def __ror__(self, value: dict[_KT2, _T], /) -> OrderedDict[_KT | _KT2, _VT | _T]: ... # type: ignore[misc] @disjoint_base class defaultdict(dict[_KT, _VT]): @@ -483,12 +488,12 @@ class defaultdict(dict[_KT, _VT]): @overload # type: ignore[override] def __or__(self, value: dict[_KT, _VT], /) -> Self: ... @overload - def __or__(self, value: dict[_T1, _T2], /) -> defaultdict[_KT | _T1, _VT | _T2]: ... + def __or__(self, value: dict[_KT2, _T], /) -> defaultdict[_KT | _KT2, _VT | _T]: ... @overload # type: ignore[override] def __ror__(self, value: dict[_KT, _VT], /) -> Self: ... @overload - def __ror__(self, value: dict[_T1, _T2], /) -> defaultdict[_KT | _T1, _VT | _T2]: ... # type: ignore[misc] + def __ror__(self, value: dict[_KT2, _T], /) -> defaultdict[_KT | _KT2, _VT | _T]: ... # type: ignore[misc] class ChainMap(MutableMapping[_KT, _VT]): maps: list[MutableMapping[_KT, _VT]] @@ -533,29 +538,29 @@ class ChainMap(MutableMapping[_KT, _VT]): if sys.version_info >= (3, 13): @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], /) -> ChainMap[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_KT], /) -> ChainMap[_KT, Any | None]: ... else: @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T]) -> ChainMap[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_KT]) -> ChainMap[_KT, Any | None]: ... @classmethod @overload # Special-case None: the user probably wants to add non-None values later. - def fromkeys(cls, iterable: Iterable[_T], value: None, /) -> ChainMap[_T, Any | None]: ... + def fromkeys(cls, iterable: Iterable[_KT], value: None, /) -> ChainMap[_KT, Any | None]: ... @classmethod @overload - def fromkeys(cls, iterable: Iterable[_T], value: _S, /) -> ChainMap[_T, _S]: ... + def fromkeys(cls, iterable: Iterable[_KT], value: _T, /) -> ChainMap[_KT, _T]: ... @overload def __or__(self, other: Mapping[_KT, _VT]) -> Self: ... @overload - def __or__(self, other: Mapping[_T1, _T2]) -> ChainMap[_KT | _T1, _VT | _T2]: ... + def __or__(self, other: Mapping[_KT2, _T]) -> ChainMap[_KT | _KT2, _VT | _T]: ... @overload def __ror__(self, other: Mapping[_KT, _VT]) -> Self: ... @overload - def __ror__(self, other: Mapping[_T1, _T2]) -> ChainMap[_KT | _T1, _VT | _T2]: ... + def __ror__(self, other: Mapping[_KT2, _T]) -> ChainMap[_KT | _KT2, _VT | _T]: ... # ChainMap.__ior__ should be kept roughly in line with MutableMapping.update() @overload # type: ignore[misc] diff --git a/stdlib/decimal.pyi b/stdlib/decimal.pyi index f16fa8aaae31..37c116ce4fd6 100644 --- a/stdlib/decimal.pyi +++ b/stdlib/decimal.pyi @@ -191,8 +191,8 @@ class Context: Emax: int capitals: int clamp: int - traps: dict[_TrapType, bool] - flags: dict[_TrapType, bool] + traps: dict[_TrapType, bool] # type: ignore[type-var] + flags: dict[_TrapType, bool] # type: ignore[type-var] def __init__( self, prec: int | None = None, @@ -201,8 +201,8 @@ class Context: Emax: int | None = None, capitals: int | None = None, clamp: int | None = None, - flags: dict[_TrapType, bool] | Container[_TrapType] | None = None, - traps: dict[_TrapType, bool] | Container[_TrapType] | None = None, + flags: dict[_TrapType, bool] | Container[_TrapType] | None = None, # type: ignore[type-var] + traps: dict[_TrapType, bool] | Container[_TrapType] | None = None, # type: ignore[type-var] ) -> None: ... def __reduce__(self) -> tuple[type[Self], tuple[Any, ...]]: ... def clear_flags(self) -> None: ... diff --git a/stdlib/inspect.pyi b/stdlib/inspect.pyi index cc39a7c9f2bc..dd7545a82a5c 100644 --- a/stdlib/inspect.pyi +++ b/stdlib/inspect.pyi @@ -487,7 +487,7 @@ class BoundArguments: _ClassTreeItem: TypeAlias = list[tuple[type, ...]] | list[_ClassTreeItem] def getclasstree(classes: list[type], unique: bool = False) -> _ClassTreeItem: ... -def walktree(classes: list[type], children: Mapping[type[Any], list[type]], parent: type[Any] | None) -> _ClassTreeItem: ... +def walktree(classes: list[type], children: Mapping[type[Any], list[type]], parent: type[Any] | None) -> _ClassTreeItem: ... # type: ignore[type-var] class Arguments(NamedTuple): args: list[str] diff --git a/stdlib/marshal.pyi b/stdlib/marshal.pyi index d72abe7758b7..54730bc2010c 100644 --- a/stdlib/marshal.pyi +++ b/stdlib/marshal.pyi @@ -22,7 +22,7 @@ _Marshallable: TypeAlias = ( | list[Any] | dict[Any, Any] | set[Any] - | frozenset[_Marshallable] + | frozenset[_Marshallable] # type: ignore[type-var] | types.CodeType | ReadableBuffer ) diff --git a/stdlib/multiprocessing/managers.pyi b/stdlib/multiprocessing/managers.pyi index 40639e867834..addc5772e56d 100644 --- a/stdlib/multiprocessing/managers.pyi +++ b/stdlib/multiprocessing/managers.pyi @@ -182,7 +182,7 @@ if sys.version_info >= (3, 14): def __iand__(self, value: AbstractSet[object], /) -> Self: ... def __or__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... def __ior__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc] - def __sub__(self, value: AbstractSet[_T | None], /) -> set[_T]: ... + def __sub__(self, value: AbstractSet[_T | None], /) -> set[_T]: ... # type: ignore[override] def __isub__(self, value: AbstractSet[object], /) -> Self: ... def __xor__(self, value: AbstractSet[_S], /) -> set[_T | _S]: ... def __ixor__(self, value: AbstractSet[_T], /) -> Self: ... # type: ignore[override,misc] diff --git a/stdlib/selectors.pyi b/stdlib/selectors.pyi index 4a3478a67552..62db2eb0a52a 100644 --- a/stdlib/selectors.pyi +++ b/stdlib/selectors.pyi @@ -25,7 +25,7 @@ class BaseSelector(metaclass=ABCMeta): def close(self) -> None: ... def get_key(self, fileobj: FileDescriptorLike) -> SelectorKey: ... @abstractmethod - def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... # type: ignore[type-var] def __enter__(self) -> Self: ... def __exit__(self, *args: Unused) -> None: ... @@ -33,7 +33,7 @@ class _BaseSelectorImpl(BaseSelector, metaclass=ABCMeta): def register(self, fileobj: FileDescriptorLike, events: int, data: Any = None) -> SelectorKey: ... def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def modify(self, fileobj: FileDescriptorLike, events: int, data: Any = None) -> SelectorKey: ... - def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... # type: ignore[type-var] class SelectSelector(_BaseSelectorImpl): def select(self, timeout: float | None = None) -> list[tuple[SelectorKey, int]]: ... diff --git a/stdlib/types.pyi b/stdlib/types.pyi index b9771ffc72da..3436d65aa864 100644 --- a/stdlib/types.pyi +++ b/stdlib/types.pyi @@ -7,6 +7,7 @@ from collections.abc import ( Callable, Coroutine, Generator, + Hashable, ItemsView, Iterable, Iterator, @@ -70,8 +71,9 @@ if sys.version_info >= (3, 15): _T1 = TypeVar("_T1") _T2 = TypeVar("_T2") -_KT_co = TypeVar("_KT_co", covariant=True) +_KT_co = TypeVar("_KT_co", bound=Hashable, covariant=True) _VT_co = TypeVar("_VT_co", covariant=True) +_KT2 = TypeVar("_KT2", bound=Hashable) # Make sure this class definition stays roughly in line with `builtins.function` @final @@ -289,8 +291,8 @@ class MappingProxyType(Mapping[_KT_co, _VT_co]): # type: ignore[type-var] # py def __class_getitem__(cls, item: Any, /) -> GenericAlias: ... def __reversed__(self) -> Iterator[_KT_co]: ... - def __or__(self, value: Mapping[_T1, _T2], /) -> dict[_KT_co | _T1, _VT_co | _T2]: ... - def __ror__(self, value: Mapping[_T1, _T2], /) -> dict[_KT_co | _T1, _VT_co | _T2]: ... + def __or__(self, value: Mapping[_KT2, _T1], /) -> dict[_KT_co | _KT2, _VT_co | _T1]: ... + def __ror__(self, value: Mapping[_KT2, _T1], /) -> dict[_KT_co | _KT2, _VT_co | _T1]: ... if sys.version_info >= (3, 12): @disjoint_base diff --git a/stdlib/typing.pyi b/stdlib/typing.pyi index 2018a835c632..083b9014ad96 100644 --- a/stdlib/typing.pyi +++ b/stdlib/typing.pyi @@ -412,10 +412,10 @@ _FT = TypeVar("_FT", bound=Callable[..., Any] | type) # These type variables are used by the container types. _S = TypeVar("_S") -_KT = TypeVar("_KT") # Key type. +_KT = TypeVar("_KT", bound=Hashable) # Key type. _VT = TypeVar("_VT") # Value type. _T_co = TypeVar("_T_co", covariant=True) # Any type covariant containers. -_KT_co = TypeVar("_KT_co", covariant=True) # Key type covariant containers. +_KT_co = TypeVar("_KT_co", bound=Hashable, covariant=True) # Key type covariant containers. _VT_co = TypeVar("_VT_co", covariant=True) # Value type covariant containers. _TC = TypeVar("_TC", bound=type[object]) @@ -727,37 +727,37 @@ class MutableSequence(Sequence[_T]): def remove(self, value: _T, /) -> None: ... def __iadd__(self, values: Iterable[_T], /) -> typing_extensions.Self: ... -class AbstractSet(Collection[_T_co]): +class AbstractSet(Collection[_KT_co]): @abstractmethod def __contains__(self, x: object, /) -> bool: ... def _hash(self) -> int: ... # Mixin methods @classmethod - def _from_iterable(cls, it: Iterable[_S], /) -> AbstractSet[_S]: ... - def __le__(self, other: AbstractSet[Any], /) -> bool: ... - def __lt__(self, other: AbstractSet[Any], /) -> bool: ... - def __gt__(self, other: AbstractSet[Any], /) -> bool: ... - def __ge__(self, other: AbstractSet[Any], /) -> bool: ... - def __and__(self, other: AbstractSet[Any], /) -> AbstractSet[_T_co]: ... - def __or__(self, other: AbstractSet[_T], /) -> AbstractSet[_T_co | _T]: ... - def __sub__(self, other: AbstractSet[Any], /) -> AbstractSet[_T_co]: ... - def __xor__(self, other: AbstractSet[_T], /) -> AbstractSet[_T_co | _T]: ... + def _from_iterable(cls, it: Iterable[_KT_co], /) -> AbstractSet[_KT_co]: ... + def __le__(self, other: AbstractSet[Hashable], /) -> bool: ... + def __lt__(self, other: AbstractSet[Hashable], /) -> bool: ... + def __gt__(self, other: AbstractSet[Hashable], /) -> bool: ... + def __ge__(self, other: AbstractSet[Hashable], /) -> bool: ... + def __and__(self, other: AbstractSet[Hashable], /) -> AbstractSet[_KT_co]: ... + def __or__(self, other: AbstractSet[_KT], /) -> AbstractSet[_KT_co | _KT]: ... + def __sub__(self, other: AbstractSet[Hashable], /) -> AbstractSet[_KT_co]: ... + def __xor__(self, other: AbstractSet[_KT], /) -> AbstractSet[_KT_co | _KT]: ... def __eq__(self, other: object, /) -> bool: ... - def isdisjoint(self, other: Iterable[Any], /) -> bool: ... + def isdisjoint(self, other: Iterable[Hashable], /) -> bool: ... -class MutableSet(AbstractSet[_T]): +class MutableSet(AbstractSet[_KT]): @abstractmethod - def add(self, value: _T, /) -> None: ... + def add(self, value: _KT, /) -> None: ... @abstractmethod - def discard(self, value: _T, /) -> None: ... + def discard(self, value: _KT, /) -> None: ... # Mixin methods def clear(self) -> None: ... - def pop(self) -> _T: ... - def remove(self, value: _T, /) -> None: ... - def __ior__(self, it: AbstractSet[_T], /) -> typing_extensions.Self: ... # type: ignore[override,misc] - def __iand__(self, it: AbstractSet[Any], /) -> typing_extensions.Self: ... - def __ixor__(self, it: AbstractSet[_T], /) -> typing_extensions.Self: ... # type: ignore[override,misc] - def __isub__(self, it: AbstractSet[Any], /) -> typing_extensions.Self: ... + def pop(self) -> _KT: ... + def remove(self, value: _KT, /) -> None: ... + def __ior__(self, it: AbstractSet[_KT], /) -> typing_extensions.Self: ... # type: ignore[override,misc] + def __iand__(self, it: AbstractSet[Hashable], /) -> typing_extensions.Self: ... + def __ixor__(self, it: AbstractSet[_KT], /) -> typing_extensions.Self: ... # type: ignore[override,misc] + def __isub__(self, it: AbstractSet[Hashable], /) -> typing_extensions.Self: ... class MappingView(Sized): __slots__ = ("_mapping",) diff --git a/stdlib/weakref.pyi b/stdlib/weakref.pyi index 3308ae42e1cf..44f4fb6a493f 100644 --- a/stdlib/weakref.pyi +++ b/stdlib/weakref.pyi @@ -1,7 +1,7 @@ from _typeshed import SupportsKeysAndGetItem from _weakref import getweakrefcount as getweakrefcount, getweakrefs as getweakrefs, proxy as proxy from _weakrefset import WeakSet as WeakSet -from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping +from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping, MutableMapping from types import GenericAlias from typing import Any, ClassVar, Generic, ParamSpec, TypeVar, final, overload from typing_extensions import Self, disjoint_base @@ -25,7 +25,7 @@ __all__ = [ _T = TypeVar("_T") _T1 = TypeVar("_T1") _T2 = TypeVar("_T2") -_KT = TypeVar("_KT") +_KT = TypeVar("_KT", bound=Hashable) _VT = TypeVar("_VT") _CallableT = TypeVar("_CallableT", bound=Callable[..., Any]) _P = ParamSpec("_P") diff --git a/stdlib/xmlrpc/client.pyi b/stdlib/xmlrpc/client.pyi index 573401f18d08..e16765c3caf1 100644 --- a/stdlib/xmlrpc/client.pyi +++ b/stdlib/xmlrpc/client.pyi @@ -111,7 +111,7 @@ class ExpatParser: # undocumented _WriteCallback: TypeAlias = Callable[[str], object] class Marshaller: - dispatch: dict[type[_Marshallable] | Literal["_arbitrary_instance"], Callable[[Marshaller, Any, _WriteCallback], None]] + dispatch: dict[type[_Marshallable] | Literal["_arbitrary_instance"], Callable[[Marshaller, Any, _WriteCallback], None]] # type: ignore[type-var] memo: dict[Any, None] data: None encoding: str | None diff --git a/stubs/dateparser/dateparser/languages/locale.pyi b/stubs/dateparser/dateparser/languages/locale.pyi index ad6ae9d283d2..074ec1aeb253 100644 --- a/stubs/dateparser/dateparser/languages/locale.pyi +++ b/stubs/dateparser/dateparser/languages/locale.pyi @@ -18,7 +18,7 @@ class Locale: def is_applicable(self, date_string: str, strip_timezone: bool = False, settings: Settings | None = None) -> bool: ... def count_applicability(self, text: str, strip_timezone: bool = False, settings: Settings | None = None) -> list[int]: ... @staticmethod - def clean_dictionary(dictionary: Mapping[_K, _V], threshold: int = 2) -> Mapping[_K, _V]: ... + def clean_dictionary(dictionary: Mapping[_K, _V], threshold: int = 2) -> Mapping[_K, _V]: ... # type: ignore[type-var] def translate(self, date_string: str, keep_formatting: bool = False, settings: Settings | None = None) -> str: ... def translate_search(self, search_string: str, settings: Settings | None = None) -> tuple[list[str], list[str]]: ... def get_wordchars_for_detection(self, settings: Settings) -> set[str]: ... diff --git a/stubs/gevent/gevent/selectors.pyi b/stubs/gevent/gevent/selectors.pyi index 12614ef1e6ff..432af20dc4e2 100644 --- a/stubs/gevent/gevent/selectors.pyi +++ b/stubs/gevent/gevent/selectors.pyi @@ -19,6 +19,6 @@ class GeventSelector(BaseSelector): def unregister(self, fileobj: FileDescriptorLike) -> SelectorKey: ... def select(self, timeout: float | None = None) -> list[tuple[SelectorKey, int]]: ... def close(self) -> None: ... - def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... + def get_map(self) -> Mapping[FileDescriptorLike, SelectorKey]: ... # type: ignore[type-var] DefaultSelector = GeventSelector diff --git a/stubs/requests-oauthlib/requests_oauthlib/oauth2_session.pyi b/stubs/requests-oauthlib/requests_oauthlib/oauth2_session.pyi index bdd4b2aa0e0e..79e769bb5e7d 100644 --- a/stubs/requests-oauthlib/requests_oauthlib/oauth2_session.pyi +++ b/stubs/requests-oauthlib/requests_oauthlib/oauth2_session.pyi @@ -11,14 +11,17 @@ _Token: TypeAlias = dict[str, Incomplete] # oauthlib.oauth2.Client.token @type_check_only class _AccessTokenResponseHook(Protocol): def __call__(self, response: requests.Response, /) -> requests.Response: ... + def __hash__(self) -> int: ... @type_check_only class _RefreshTokenResponseHook(Protocol): def __call__(self, response: requests.Response, /) -> requests.Response: ... + def __hash__(self) -> int: ... @type_check_only class _ProtectedRequestHook(Protocol): def __call__(self, url, headers, data, /) -> tuple[Incomplete, Incomplete, Incomplete]: ... + def __hash__(self) -> int: ... @type_check_only class _ComplianceHooks(TypedDict):