diff --git a/stdlib/@tests/test_cases/builtins/check_dict.py b/stdlib/@tests/test_cases/builtins/check_dict.py index fe74ad49408e..c47da721c331 100644 --- a/stdlib/@tests/test_cases/builtins/check_dict.py +++ b/stdlib/@tests/test_cases/builtins/check_dict.py @@ -1,7 +1,7 @@ from __future__ import annotations import os -from typing import Any, Dict, Generic, Iterable, Mapping, TypeVar, Union +from typing import Any, Dict, Generic, Iterable, Literal, Mapping, TypeVar, Union from typing_extensions import Self, assert_type ################################################################### @@ -103,6 +103,16 @@ def test_iterable_tuple_overload(x: Iterable[tuple[int, str]]) -> dict[int, str] result = d_str.get("key", int_value) # type: ignore[arg-type] +def test_dict_signature_overlapping_type(d: dict[Literal["foo", "bar"], int], key: str) -> None: + # Note: annotations also allow using keys of a disjoint type (e.g., int), + # linters / type checkers are free to issue warnings in such cases. + # statically, a .get(arg) is superfluous if the intersection of the + # dict key type and the argument type is empty. + # So we only test a case with non-empty intersection here. + d.get(key) + d.pop(key) + + # Return values also make things weird # Pyright doesn't have a version of no-any-return, diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 5695b17ca36d..651db8e1d23f 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -1220,17 +1220,19 @@ class dict(MutableMapping[_KT, _VT]): def fromkeys(cls, iterable: Iterable[_T], value: _S, /) -> dict[_T, _S]: ... # Positional-only in dict, but not in MutableMapping @overload # type: ignore[override] - def get(self, key: _KT, default: None = None, /) -> _VT | None: ... + def get(self, key: object, default: None = None, /) -> _VT | None: ... @overload - def get(self, key: _KT, default: _VT, /) -> _VT: ... + def get(self, key: object, default: _VT, /) -> _VT: ... @overload - def get(self, key: _KT, default: _T, /) -> _VT | _T: ... + def get(self, key: object, default: _T, /) -> _VT | _T: ... + # dict.pop allows arbitrary types, which matches runtime semantics. + # linters may choose to warn if the given type does not overlap with the key type @overload - def pop(self, key: _KT, /) -> _VT: ... + def pop(self, key: object, /) -> _VT: ... @overload - def pop(self, key: _KT, default: _VT, /) -> _VT: ... + def pop(self, key: object, default: _VT, /) -> _VT: ... @overload - def pop(self, key: _KT, default: _T, /) -> _VT | _T: ... + def pop(self, key: object, default: _T, /) -> _VT | _T: ... def __len__(self) -> int: ... def __getitem__(self, key: _KT, /) -> _VT: ... def __setitem__(self, key: _KT, value: _VT, /) -> None: ... diff --git a/stdlib/collections/__init__.pyi b/stdlib/collections/__init__.pyi index 95f13b0c8dd2..cb29c756122e 100644 --- a/stdlib/collections/__init__.pyi +++ b/stdlib/collections/__init__.pyi @@ -382,11 +382,11 @@ class OrderedDict(dict[_KT, _VT]): def setdefault(self, key: _KT, default: _VT) -> _VT: ... # Same as dict.pop, but accepts keyword arguments @overload - def pop(self, key: _KT) -> _VT: ... + def pop(self, key: object) -> _VT: ... @overload - def pop(self, key: _KT, default: _VT) -> _VT: ... + def pop(self, key: object, default: _VT) -> _VT: ... @overload - def pop(self, key: _KT, default: _T) -> _VT | _T: ... + def pop(self, key: object, default: _T) -> _VT | _T: ... def __eq__(self, value: object, /) -> bool: ... @overload def __or__(self, value: dict[_KT, _VT], /) -> Self: ... diff --git a/stdlib/importlib/metadata/__init__.pyi b/stdlib/importlib/metadata/__init__.pyi index 9286e92331c8..9ae3eb272fba 100644 --- a/stdlib/importlib/metadata/__init__.pyi +++ b/stdlib/importlib/metadata/__init__.pyi @@ -165,11 +165,11 @@ if sys.version_info >= (3, 10) and sys.version_info < (3, 12): class Deprecated(Generic[_KT, _VT]): def __getitem__(self, name: _KT) -> _VT: ... @overload - def get(self, name: _KT, default: None = None) -> _VT | None: ... + def get(self, name: object, default: None = None) -> _VT | None: ... @overload - def get(self, name: _KT, default: _VT) -> _VT: ... + def get(self, name: object, default: _VT) -> _VT: ... @overload - def get(self, name: _KT, default: _T) -> _VT | _T: ... + def get(self, name: object, default: _T) -> _VT | _T: ... def __iter__(self) -> Iterator[_KT]: ... def __contains__(self, *args: object) -> bool: ... def keys(self) -> dict_keys[_KT, _VT]: ... diff --git a/stdlib/mailbox.pyi b/stdlib/mailbox.pyi index 89bd998b4dfe..7aacfb2ad0b8 100644 --- a/stdlib/mailbox.pyi +++ b/stdlib/mailbox.pyi @@ -88,7 +88,7 @@ class Mailbox(Generic[_MessageT]): def __len__(self) -> int: ... def clear(self) -> None: ... @overload - def pop(self, key: str, default: None = None) -> _MessageT | None: ... + def pop(self, key: str) -> _MessageT | None: ... @overload def pop(self, key: str, default: _T) -> _MessageT | _T: ... def popitem(self) -> tuple[str, _MessageT]: ... diff --git a/stubs/boltons/boltons/cacheutils.pyi b/stubs/boltons/boltons/cacheutils.pyi index 40e786e61bd8..307560456ce6 100644 --- a/stubs/boltons/boltons/cacheutils.pyi +++ b/stubs/boltons/boltons/cacheutils.pyi @@ -24,16 +24,16 @@ class LRI(dict[_KT, _VT]): def __setitem__(self, key: _KT, value: _VT) -> None: ... def __getitem__(self, key: _KT) -> _VT: ... @overload - def get(self, key: _KT, default: None = None) -> _VT | None: ... + def get(self, key: object, default: None = None) -> _VT | None: ... @overload - def get(self, key: _KT, default: _VT) -> _VT: ... + def get(self, key: object, default: _VT) -> _VT: ... @overload - def get(self, key: _KT, default: _T) -> _T | _VT: ... + def get(self, key: object, default: _T) -> _T | _VT: ... def __delitem__(self, key: _KT) -> None: ... @overload - def pop(self, key: _KT) -> _VT: ... + def pop(self, key: object) -> _VT: ... @overload - def pop(self, key: _KT, default: _T) -> _T | _VT: ... + def pop(self, key: object, default: _T) -> _T | _VT: ... def popitem(self) -> tuple[_KT, _VT]: ... def clear(self) -> None: ... def copy(self) -> Self: ... diff --git a/stubs/boltons/boltons/dictutils.pyi b/stubs/boltons/boltons/dictutils.pyi index 5e609ef9af13..e725160fb806 100644 --- a/stubs/boltons/boltons/dictutils.pyi +++ b/stubs/boltons/boltons/dictutils.pyi @@ -55,7 +55,7 @@ class OneToOne(dict[_KT, _VT]): inv: OneToOne[_VT, _KT] def clear(self) -> None: ... def copy(self) -> Self: ... - def pop(self, key: _KT, default: _VT | _T = ...) -> _VT | _T: ... + def pop(self, key: object, default: _VT | _T = ...) -> _VT | _T: ... def popitem(self) -> tuple[_KT, _VT]: ... def setdefault(self, key: _KT, default: _VT | None = None) -> _VT: ... @classmethod diff --git a/stubs/icalendar/icalendar/caselessdict.pyi b/stubs/icalendar/icalendar/caselessdict.pyi index 683033b27c19..5c2f0bad457b 100644 --- a/stubs/icalendar/icalendar/caselessdict.pyi +++ b/stubs/icalendar/icalendar/caselessdict.pyi @@ -18,7 +18,7 @@ class CaselessDict(OrderedDict[str, _VT]): def __setitem__(self, key: str | bytes, value: _VT) -> None: ... def __delitem__(self, key: str | bytes) -> None: ... def __contains__(self, key: str | bytes) -> bool: ... # type: ignore[override] - @overload + @overload # type: ignore[override] def get(self, key: str | bytes, default: None = None) -> _VT: ... @overload def get(self, key: str | bytes, default: _VT) -> _VT: ... diff --git a/stubs/oauthlib/oauthlib/common.pyi b/stubs/oauthlib/oauthlib/common.pyi index 15112d51863c..078a2200f698 100644 --- a/stubs/oauthlib/oauthlib/common.pyi +++ b/stubs/oauthlib/oauthlib/common.pyi @@ -53,9 +53,9 @@ class CaseInsensitiveDict(dict[str, Incomplete]): def __delitem__(self, k: str) -> None: ... def __getitem__(self, k: str): ... @overload - def get(self, k: str, default: None = None) -> Incomplete | None: ... + def get(self, k: object, default: None = None) -> Incomplete | None: ... @overload - def get(self, k: str, default): ... + def get(self, k: object, default): ... def __setitem__(self, k: str, v) -> None: ... def update(self, *args, **kwargs) -> None: ... diff --git a/stubs/requests/requests/structures.pyi b/stubs/requests/requests/structures.pyi index 53dd5f565154..9894caf4d0f2 100644 --- a/stubs/requests/requests/structures.pyi +++ b/stubs/requests/requests/structures.pyi @@ -20,6 +20,6 @@ class LookupDict(dict[str, _VT]): def __getitem__(self, key: str) -> _VT | None: ... # type: ignore[override] def __setattr__(self, attr: str, value: _VT, /) -> None: ... @overload - def get(self, key: str, default: None = None) -> _VT | None: ... + def get(self, key: object, default: None = None) -> _VT | None: ... @overload - def get(self, key: str, default: _D | _VT) -> _D | _VT: ... + def get(self, key: object, default: _D | _VT) -> _D | _VT: ... diff --git a/stubs/www-authenticate/www_authenticate.pyi b/stubs/www-authenticate/www_authenticate.pyi index 9dbaaa1ced9a..60b47c90ea4d 100644 --- a/stubs/www-authenticate/www_authenticate.pyi +++ b/stubs/www-authenticate/www_authenticate.pyi @@ -18,7 +18,7 @@ class CaseFoldedOrderedDict(OrderedDict[str, _VT]): def __setitem__(self, key: _SupportsCasefold | _SupportsLower, value: _VT) -> None: ... def __contains__(self, key: _SupportsCasefold | _SupportsLower) -> bool: ... # type: ignore[override] # See overloads for dict class: - @overload + @overload # type: ignore[override] def get(self, key: _SupportsCasefold | _SupportsLower, default: None = None) -> _VT | None: ... @overload def get(self, key: _SupportsCasefold | _SupportsLower, default: _VT) -> _VT: ... diff --git a/stubs/yt-dlp/yt_dlp/utils/networking.pyi b/stubs/yt-dlp/yt_dlp/utils/networking.pyi index 1d3d18310dd3..fa60f5c66e42 100644 --- a/stubs/yt-dlp/yt_dlp/utils/networking.pyi +++ b/stubs/yt-dlp/yt_dlp/utils/networking.pyi @@ -21,11 +21,11 @@ class HTTPHeaderDict(dict[str, str]): @overload def get(self, key: str, /, default: type[NO_DEFAULT] | _T = ...) -> str | _T | type[NO_DEFAULT]: ... @overload - def pop(self, key: str, /) -> str: ... + def pop(self, key: object, /) -> str: ... @overload - def pop(self, key: str, /, default: _T) -> str | _T: ... + def pop(self, key: object, /, default: _T) -> str | _T: ... @overload - def pop(self, key: str, /, default: type[NO_DEFAULT] | _T | str = ...) -> str | _T | type[NO_DEFAULT]: ... + def pop(self, key: object, /, default: type[NO_DEFAULT] | _T | str = ...) -> str | _T | type[NO_DEFAULT]: ... @overload def setdefault(self, key: str, /) -> str: ... @overload