Mypy incorrectly warns when passing literals as kwarg keywords
Bug Report
from typing import Any, Dict, Literal
kw: Dict[Literal["a", "b"], Any]
def func(a, b):
pass
func(**kw)
Leads to
main.py:8: error: Keywords must be strings
https://mypy-play.net/?mypy=latest&python=3.9&gist=582cf5e8c0a6e6a5881d391da64e1455
Expected Behavior Expect this to be allowable - as these literals count as strings
Arguably this should still be a (different) error, because the a and b args are required and a Dict[Literal["a", "b"], Any] may not contain values for a or b.
@JelleZijlstra Yes.
This should be fine, I think:
from typing import Any, Dict, Literal
kw: Dict[Literal["a", "b"], Any]
def func(a=None, b=None):
pass
func(**kw)
Hey @JukkaL I want to work on this. Can you please assign it to me?
@vickyhuo Done!
Can I work on it in the future?
@JelleZijlstra Yes.
This should be fine, I think:
from typing import Any, Dict, Literal kw: Dict[Literal["a", "b"], Any] def func(a=None, b=None): pass func(**kw)
still it having a problem
I believe the problem is in subtype check presented below:
This case is not considered as subtype:
(Pdb) left
typing.Mapping[Union[Literal['a'], Literal['b']], Any]
(Pdb) right
typing.Mapping[builtins.str, Any]
(Pdb) is_subtype(left, right)
False
However this one is:
(Pdb) left
Union[Literal['a'], Literal['b']]
(Pdb) right
builtins.str
(Pdb) is_subtype(left, right)
True
The negative result of first presented subtype check leads to not considering Dict[Literal["a", "b"], Any] as a valid **kwarg type.
Hi @kamilturek, I believe that is the problem as well. I'm currently still working on a fix
Sounds like this is just another symptom of Mapping not being covariant in its key type
@hauntsaninja What's the reason of this?
It's unsafe, see https://github.com/python/typing/issues/445
Reading through this issue, I was trying to figure out if the issue was that kw wasn't assigned any values in the sample code. However, I can validate that even with a dict assigned to kw, the issue persists, i.e. the same error message is output by mypy. Additionally, PyCharm gives a hint when assigning the value as follows.
from typing import Any, Dict, Literal
kw: Dict[Literal["a", "b"], Any]
kw = {"a": 1, "b": 2} # Expected type 'dict[Literal["a", "b"], Any]', got 'dict[str, int]' instead
def func(a, b):
pass
func(**kw)
Seems to echo @kamilturek's discovery in the debugger.
Hi, Is anyone working on this issue? If not, please assign me this issue, and please help me out with some references from where I can start digging into it.
Looks like #10237 is a PR trying to solve this
Perhaps one way to help is to help review 10237 - by reading the code - and checking it out and running it to double check that it fixes the issue. I know the maintainers appreciate when folks do code review.
In case you're not familiar - github renders this in the header with "may be fixed by" -

Note this also happens with classes inheriting from str, such as enum.StrEnum.
#13674 may be a dupe as well