From 69bb68bf51b8731809a33e8cfce2bf5c364998e6 Mon Sep 17 00:00:00 2001 From: Randolf Scholz Date: Sun, 8 Mar 2026 22:03:50 +0100 Subject: [PATCH] simplified dict.get to not require overloads --- .../@tests/test_cases/builtins/check_dict.py | 31 ++++++++++--------- stdlib/builtins.pyi | 9 ++---- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/stdlib/@tests/test_cases/builtins/check_dict.py b/stdlib/@tests/test_cases/builtins/check_dict.py index fe74ad49408e..57a7e9b30e70 100644 --- a/stdlib/@tests/test_cases/builtins/check_dict.py +++ b/stdlib/@tests/test_cases/builtins/check_dict.py @@ -71,34 +71,33 @@ def test_iterable_tuple_overload(x: Iterable[tuple[int, str]]) -> dict[int, str] int_value = 1 assert_type(d_any["key"], Any) -assert_type(d_any.get("key"), Union[Any, None]) -assert_type(d_any.get("key", None), Union[Any, None]) +assert_type(d_any.get("key"), Any | None) +assert_type(d_any.get("key", None), Any | None) assert_type(d_any.get("key", any_value), Any) -assert_type(d_any.get("key", str_value), Any) -assert_type(d_any.get("key", int_value), Any) +assert_type(d_any.get("key", str_value), Any | str) +assert_type(d_any.get("key", int_value), Any | int) assert_type(d_str["key"], str) -assert_type(d_str.get("key"), Union[str, None]) -assert_type(d_str.get("key", None), Union[str, None]) +assert_type(d_str.get("key"), str | None) +assert_type(d_str.get("key", None), str | None) # Pyright has str instead of Any here -assert_type(d_str.get("key", any_value), Any) # pyright: ignore[reportAssertTypeFailure] +assert_type(d_str.get("key", any_value), str | Any) assert_type(d_str.get("key", str_value), str) -assert_type(d_str.get("key", int_value), Union[str, int]) +assert_type(d_str.get("key", int_value), str | int) # Now with context! result: str result = d_any["key"] result = d_any.get("key") # type: ignore[assignment] result = d_any.get("key", None) # type: ignore[assignment] -result = d_any.get("key", any_value) -result = d_any.get("key", str_value) -result = d_any.get("key", int_value) +result = d_any.get("key", any_value) # OK +result = d_any.get("key", str_value) # OK +result = d_any.get("key", int_value) # type: ignore[assignment] result = d_str["key"] result = d_str.get("key") # type: ignore[assignment] result = d_str.get("key", None) # type: ignore[assignment] -# Pyright has str | None here, see https://github.com/microsoft/pyright/discussions/9570 -result = d_str.get("key", any_value) # pyright: ignore[reportAssignmentType] +result = d_str.get("key", any_value) result = d_str.get("key", str_value) result = d_str.get("key", int_value) # type: ignore[arg-type] @@ -143,8 +142,10 @@ def test9() -> str: return d_str.get("key", None) # type: ignore[return-value] -def test10() -> str: - return d_str.get("key", any_value) # type: ignore[no-any-return] +# Pyright doesn't have a version of no-any-return, +# and mypy doesn't have a type: ignore that pyright will ignore. +# def test10() -> str: +# return d_str.get("key", any_value) # mypy: ignore[no-any-return] def test11() -> str: diff --git a/stdlib/builtins.pyi b/stdlib/builtins.pyi index 5657ac74a9ac..9ed1b6facee8 100644 --- a/stdlib/builtins.pyi +++ b/stdlib/builtins.pyi @@ -96,6 +96,7 @@ _SupportsAnextT_co = TypeVar("_SupportsAnextT_co", bound=SupportsAnext[Any], cov _AwaitableT = TypeVar("_AwaitableT", bound=Awaitable[Any]) _AwaitableT_co = TypeVar("_AwaitableT_co", bound=Awaitable[Any], covariant=True) _P = ParamSpec("_P") +_NoneDefaultT = TypeVar("_NoneDefaultT", default=None) # Type variables for slice _StartT_co = TypeVar("_StartT_co", covariant=True, default=Any) # slice -> slice[Any, Any, Any] @@ -1218,13 +1219,7 @@ class dict(MutableMapping[_KT, _VT]): @classmethod @overload 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: ... - @overload - def get(self, key: _KT, default: _VT, /) -> _VT: ... - @overload - def get(self, key: _KT, default: _T, /) -> _VT | _T: ... + def get(self, key: _KT, default: _NoneDefaultT = None, /) -> _VT | _NoneDefaultT: ... # type: ignore[assignment] @overload def pop(self, key: _KT, /) -> _VT: ... @overload