-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
Bug Report
A an if statement like if x in some_dict.keys() doesn't narrow the type of x to the type of the key of some_dict.
This is in contrast with if x in some_dict which does correctly narrow.
(I had a search and didn't find a similar existing discussion, apologies if this isn't the case)
To Reproduce
Run mypy over the following:
from collections.abc import KeysView
def get_via_keys(key: str | None, data: dict[str, str]) -> str:
if key in data.keys():
# error: Incompatible return value type (got "Optional[str]", expected "str")
return key
return "value"
def get_via_keys_explicit_typing(key: str | None, data: dict[str, str]) -> str:
keys: KeysView[str] = data.keys()
if key in keys:
# error: Incompatible return value type (got "Optional[str]", expected "str")
return key
return "value"
def get_check_dict_membership(key: str | None, data: dict[str, str]) -> str:
if key in data:
# OK
return key
return "value"Expected Behavior
mypy correctly narrows the type in each of the if statements and the script passes.
Actual Behavior
mypy reports failures as:
script.py:7: error: Incompatible return value type (got "Optional[str]", expected "str")
script.py:15: error: Incompatible return value type (got "Optional[str]", expected "str")
Found 2 errors in 1 file (checked 1 source file)
Your Environment
- Mypy version used:
0.971andmypy 0.980+dev.e69bd9a7270daac8db409e8d08400d9d32367c32 (compiled: no)(currentmaster) - Mypy command-line flags:
mypy <name-of-file-above> - Mypy configuration options from
mypy.ini(and other config files): the above was run from the root of this project (so whatever's configured there) - Python version used:
Python 3.10.5 - Operating system and version: Arch Linux (kernel 5.18.15)
The following allows get_via_keys above to pass under mypy
diff --git a/mypy/checker.py b/mypy/checker.py
index e64cea7b4..852fe8fab 100644
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -6285,6 +6285,7 @@ def builtin_item_type(tp: Type) -> Optional[Type]:
"builtins.dict",
"builtins.set",
"builtins.frozenset",
+ "_collections_abc.dict_keys",
]:
if not tp.args:
# TODO: fix tuple in lib-stub/builtins.pyi (it should be generic).Though I'm not sure how appropriate it would be given the note in the docs for that function:
Note: this is only OK for built-in containers, where we know the behavior of __contains__.
Also, dict_keys is undocumented and a quick git grep --word-regexp 'dict_keys' didn't show much usage for it outside of typeshed.