Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion stdlib/@tests/test_cases/builtins/check_dict.py
Original file line number Diff line number Diff line change
@@ -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

###################################################################
Expand Down Expand Up @@ -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,
Expand Down
14 changes: 8 additions & 6 deletions stdlib/builtins.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
6 changes: 3 additions & 3 deletions stdlib/collections/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
6 changes: 3 additions & 3 deletions stdlib/importlib/metadata/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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]: ...
Expand Down
2 changes: 1 addition & 1 deletion stdlib/mailbox.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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]: ...
Expand Down
10 changes: 5 additions & 5 deletions stubs/boltons/boltons/cacheutils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
2 changes: 1 addition & 1 deletion stubs/boltons/boltons/dictutils.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion stubs/icalendar/icalendar/caselessdict.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
4 changes: 2 additions & 2 deletions stubs/oauthlib/oauthlib/common.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...

Expand Down
4 changes: 2 additions & 2 deletions stubs/requests/requests/structures.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
2 changes: 1 addition & 1 deletion stubs/www-authenticate/www_authenticate.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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: ...
Expand Down
6 changes: 3 additions & 3 deletions stubs/yt-dlp/yt_dlp/utils/networking.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down