Open
Description
Bug Report
When using d or {}
where d
is a subclass of dict
or something that implements the SupportsKeysAndGetItem
protocol can lead to errors/different behaviour in downstream code than when it is a dict
directly. There errors are things indicating the Never
key type of {}
is causing problem:
Invalid index type "str" for "DictSubclass | dict[Never, Never]"; expected type "Never" [index]
Unpacked dict entry 0 has incompatible type "SKAGI | dict[Never, Never]"; expected "SupportsKeysAndGetItem[str, int]" [dict-item]
This is potentially the same as #17684, but felt different.
(As always, thanks for Mypy!)
To Reproduce
https://mypy-play.net/?mypy=latest&python=3.12&gist=a7075c4918e6e95f4f9429bd261aa4c0
from typing import Iterable
class DictSubclass(dict[str, int]): pass
class SKAGI: # SupportsKeysAndGetItem
def keys(self) -> Iterable[str]:
return ['foo']
def __getitem__(self, __key: str) -> int:
return 1
def dict_subclass(d: None | DictSubclass):
if d is not None: # proving the basic operations work:
d["x"] # no error
{**d} # no error
index = (d or {})["x"] # error: Invalid index type "str" for "DictSubclass | dict[Never, Never]"; expected type "Never" [index]
get = (d or {}).get("x") # error: No overload variant of "get" of "dict" matches argument type "str" [call-overload]
splat = {**(d or {})} # error: Unpacked dict entry 0 has incompatible type "DictSubclass | dict[Never, Never]"; expected "SupportsKeysAndGetItem[str, int]" [dict-item]
def skagi(d: None | SKAGI):
if d is not None: # proving the basic operations work:
d["x"] # no error
{**d} # no error
index = (d or {})["x"] # error: Invalid index type "str" for "SKAGI | dict[Never, Never]"; expected type "Never" [index]
splat = {**(d or {})} # error: Unpacked dict entry 0 has incompatible type "SKAGI | dict[Never, Never]"; expected "SupportsKeysAndGetItem[str, int]" [dict-item]
# using the normal dict for comparison:
def dict_builtin(d: None | dict[str, int]):
index = (d or {})["x"] # no error
get = (d or {}).get("x") # no error
splat = {**(d or {})} # no error
Expected Behavior
I'd expect the subclass and SupportsKeysAndGetItem
-implementing type to behave the same as the normal dict
instance, where the Never
key arg is unified and/or ignored appropriately.
Actual Behavior
main.py:17: error: Invalid index type "str" for "DictSubclass | dict[Never, Never]"; expected type "Never" [index]
main.py:18: error: No overload variant of "get" of "dict" matches argument type "str" [call-overload]
main.py:18: note: Possible overload variants:
main.py:18: note: def get(self, Never, /) -> None
main.py:18: note: def get(self, Never, Never, /) -> Never
main.py:18: note: def [_T] get(self, Never, _T, /) -> _T
main.py:19: error: Unpacked dict entry 0 has incompatible type "DictSubclass | dict[Never, Never]"; expected "SupportsKeysAndGetItem[str, int]" [dict-item]
main.py:26: error: Invalid index type "str" for "SKAGI | dict[Never, Never]"; expected type "Never" [index]
main.py:27: error: Unpacked dict entry 0 has incompatible type "SKAGI | dict[Never, Never]"; expected "SupportsKeysAndGetItem[str, int]" [dict-item]
Found 5 errors in 1 file (checked 1 source file)
Your Environment
- Mypy version used: 1.11.2
- Mypy command-line flags: N/A
- Mypy configuration options from
mypy.ini
(and other config files): N/A - Python version used: 3.12