You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I often feel I have to put too much effort into informing mypy that some variables can only hold a finite set of values. It would be helpful if mypy was a bit smarter in the way it infers Literal types.
Pitch
Here are some concrete examples:
fromtypingimportLiteraldefletter_v1(number: int) ->Literal["a", "b", "c"]:
ifnumber==1:
letter="a"elifnumber==2:
letter="b"else:
letter="c"# Incompatible return value type (got "str", expected "Literal['a', 'b', 'c']") [return-value]returnletterdefletter_v2(number: int) ->Literal["a", "b", "c"]:
letter="a"ifnumber==1else"b"ifnumber==2else"c"# Incompatible return value type (got "str", expected "Literal['a', 'b', 'c']") [return-value]returnletterdefletter_v3(number: int) ->Literal["a", "b", "c"]:
letter= ("a", "b", "c")[number]
# Incompatible return value type (got "str", expected "Literal['a', 'b', 'c']") [return-value]returnletter
Ideally, I think I should get away without having to specify the type of letter in any of the concrete examples here. A human reviewing this code would easily conclude that there is no issue here, yet mypy struggles.
Mypy uses joins rather than unions when combining types during code flow analysis. Even if mypy were to narrow types to literals upon assignments, it would combine Literal["a"], Literal["b"] and Literal["c"] into str rather than Literal["a", "b", "c"].
I've been lobbying for item 2 to be changed for quite a while. If you filter issues on the tag "topic-join-vs-union", you will see that there are more than 50 open issues that would be addressed by this change.
For item 1, I think it's unlikely that the developers of mypy would make that change. It would be too disruptive to existing mypy users, and there are other many other design decisions that would need to be modified as well (e.g. inference of list, set, dict and tuple expressions that include literals).
Thanks @erictraut for sharing your insights on this. It is good to get a sense of the design decisions that led us here.
As an aside, I wonder if it could be possible to use the return signature of the function as an upper bound for any variable returned from it. That is, having the type checker infer that -> Literal["a", "b", "c"] also implies that the developer intends letter to at least be no wider typed than Literal["a", "b", "c"], since return letter is present in the function.
This approach might not be worth anything if your suggestions are implemented, but if not, this might be a third approach.
Activity
erictraut commentedon Jun 14, 2023
There are two separate issues that prevent mypy from type checking this code without errors.
letterwill not be narrowed toLiteral["a"]after the statementletter = "a".Literal["a"],Literal["b"]andLiteral["c"]intostrrather thanLiteral["a", "b", "c"].I've been lobbying for item 2 to be changed for quite a while. If you filter issues on the tag "topic-join-vs-union", you will see that there are more than 50 open issues that would be addressed by this change.
For item 1, I think it's unlikely that the developers of mypy would make that change. It would be too disruptive to existing mypy users, and there are other many other design decisions that would need to be modified as well (e.g. inference of list, set, dict and tuple expressions that include literals).
FWIW, the above code type checks fine in pyright.
harahu commentedon Jun 15, 2023
Thanks @erictraut for sharing your insights on this. It is good to get a sense of the design decisions that led us here.
As an aside, I wonder if it could be possible to use the return signature of the function as an upper bound for any variable returned from it. That is, having the type checker infer that
-> Literal["a", "b", "c"]also implies that the developer intendsletterto at least be no wider typed thanLiteral["a", "b", "c"], sincereturn letteris present in the function.This approach might not be worth anything if your suggestions are implemented, but if not, this might be a third approach.