mypy
mypy copied to clipboard
mypy incorrectly tags function argument TypeVar with return type when called from a caller with the same signature
Bug Report
mypy incorrectly tags a function argument of type Mapping[K, V] where K and V are TypeVar with the return value of the caller function.
To Reproduce
The below small program demonstrates the issue:
from typing import Dict, Mapping, TypeVar, Union
K = TypeVar("K")
V = TypeVar("V")
K2 = TypeVar("K2")
V2 = TypeVar("V2")
def func(one: Dict[K, V], two: Mapping[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
reveal_type(one)
reveal_type(two)
return {}
def caller(arg1: Mapping[K, V], arg2: Mapping[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
reveal_type(arg1)
reveal_type(arg2)
_arg1 = arg1 if isinstance(arg1, dict) else dict(arg1)
return func(_arg1, arg2)
Expected Behavior
mypy should succeed without an error.
$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "typing.Mapping[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
Success: no issues found in 1 source file
Actual Behavior
mypy complains with a very weird error, even though the revealed types are correct
$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "typing.Mapping[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:19: error: Argument 2 to "func" has incompatible type "Mapping[K2, V2]"; expected "Mapping[Union[K, K2], Union[V, V2]]" [arg-type]
Found 1 error in 1 file (checked 1 source file)
More Info
Note, if I change the type signature of the caller, it ends up changing the type signature of the called function as well:
from typing import Dict, Mapping, TypeVar, Union
K = TypeVar("K")
V = TypeVar("V")
K2 = TypeVar("K2")
V2 = TypeVar("V2")
def func(one: Dict[K, V], two: Mapping[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
reveal_type(one)
reveal_type(two)
return {}
def caller(arg1: Mapping[K, V], arg2: Mapping[K2, V2]) -> None:
reveal_type(arg1)
reveal_type(arg2)
_arg1 = arg1 if isinstance(arg1, dict) else dict(arg1)
func(_arg1, arg2)
will return:
$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "typing.Mapping[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "typing.Mapping[K2`-3, V2`-4]"
Success: no issues found in 1 source file
Your Environment
- Mypy version used:
mypy 0.991 (compiled: yes) - Mypy command-line flags:
--strict - Mypy configuration options from
mypy.ini(and other config files):ignore_missing_imports = true - Mypy plugins:
sqlalchemy.ext.mypy.plugin,pydantic.mypyandnumpy.typing.mypy_plugin - Python version used:
Python 3.9.17
This is not specific to Mapping and is reproducible with Dict as well. Looks like TypeVar along with having two functions with the same return type will cause this issue.
Below program reproduces this issue with Dict, instead of Mapping
from typing import Dict, TypeVar, Union
K = TypeVar("K")
V = TypeVar("V")
K2 = TypeVar("K2")
V2 = TypeVar("V2")
def func(one: Dict[K, V], two: Dict[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
reveal_type(one)
reveal_type(two)
return {}
def caller(arg1: Dict[K, V], arg2: Dict[K2, V2]) -> Dict[Union[K, K2], Union[V, V2]]:
reveal_type(arg1)
reveal_type(arg2)
_arg1 = arg1 if isinstance(arg1, dict) else dict(arg1)
return func(_arg1, arg2)
returns
$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "builtins.dict[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "builtins.dict[K2`-3, V2`-4]"
break_mypy.py:19: error: Argument 1 to "func" has incompatible type "Dict[K, V]"; expected "Dict[Union[K, K2], Union[V, V2]]" [arg-type]
break_mypy.py:19: error: Argument 2 to "func" has incompatible type "Dict[K2, V2]"; expected "Dict[Union[K, K2], Union[V, V2]]" [arg-type]
Found 2 errors in 1 file (checked 1 source file)
This is reproducible on newest mypy and python versions as well:
$ mypy --version
mypy 1.8.0 (compiled: yes)
$ python --version
Python 3.11.4
$ mypy --strict break_mypy.py
break_mypy.py:10: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:11: note: Revealed type is "builtins.dict[K2`-3, V2`-4]"
break_mypy.py:16: note: Revealed type is "builtins.dict[K`-1, V`-2]"
break_mypy.py:17: note: Revealed type is "builtins.dict[K2`-3, V2`-4]"
break_mypy.py:19: error: Argument 1 to "func" has incompatible type "dict[K, V]"; expected "dict[K | K2, V | V2]" [arg-type]
break_mypy.py:19: error: Argument 2 to "func" has incompatible type "dict[K2, V2]"; expected "dict[K | K2, V | V2]" [arg-type]
Found 2 errors in 1 file (checked 1 source file)