mypy icon indicating copy to clipboard operation
mypy copied to clipboard

Mypy incorrectly warns when passing literals as kwarg keywords

Open nipunn1313 opened this issue 4 years ago • 16 comments

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

nipunn1313 avatar Feb 04 '21 14:02 nipunn1313

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 avatar Feb 04 '21 14:02 JelleZijlstra

@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)

JukkaL avatar Feb 04 '21 19:02 JukkaL

Hey @JukkaL I want to work on this. Can you please assign it to me?

vickyhuo avatar Feb 05 '21 00:02 vickyhuo

@vickyhuo Done!

JukkaL avatar Feb 06 '21 11:02 JukkaL

Can I work on it in the future?

Uttam-Singhh avatar Feb 12 '21 16:02 Uttam-Singhh

@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

Soumokanti123 avatar Mar 13 '21 05:03 Soumokanti123

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.

kamilturek avatar Mar 15 '21 22:03 kamilturek

Hi @kamilturek, I believe that is the problem as well. I'm currently still working on a fix

vickyhuo avatar Mar 17 '21 13:03 vickyhuo

Sounds like this is just another symptom of Mapping not being covariant in its key type

hauntsaninja avatar Mar 17 '21 14:03 hauntsaninja

@hauntsaninja What's the reason of this?

kamilturek avatar Mar 17 '21 19:03 kamilturek

It's unsafe, see https://github.com/python/typing/issues/445

hauntsaninja avatar Mar 17 '21 19:03 hauntsaninja

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.

jp-larose avatar May 03 '21 21:05 jp-larose

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.

pulkit-30 avatar Oct 05 '21 19:10 pulkit-30

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" - image

nipunn1313 avatar Oct 06 '21 17:10 nipunn1313

Note this also happens with classes inheriting from str, such as enum.StrEnum.

NicholasTNG avatar Nov 18 '24 13:11 NicholasTNG

#13674 may be a dupe as well

AaronDMarasco avatar Dec 10 '25 16:12 AaronDMarasco