Here’s another example, contrasting the behavior of mypy and pyright with Enum and Literal. From a typing perspective, my colleagues and I like to view Literal as a typing shorthand for creating an Enum class, but pyright makes this hard to do because of the type “widening” going on.
from enum import Enum
from typing import Literal
class MyEnumAB(Enum):
A = 1
B = 2
def enum_returnset(thelist: list[MyEnumAB]) -> set[MyEnumAB]:
y = set([x for x in thelist])
reveal_type(y)
return y
MyLiteral = type[Literal[1, 2]]
def lit_returnset(thelist: list[MyLiteral]) -> set[MyLiteral]:
y = set([x for x in thelist])
reveal_type(y)
return y
pyright output
enumadd.py
enumadd.py:12:17 - information: Type of "y" is "set[MyEnumAB]"
enumadd.py:21:17 - information: Type of "y" is "set[type[int]]"
enumadd.py:22:12 - error: Type "set[type[int]]" is not assignable to return type "set[MyLiteral]"
"set[type[int]]" is not assignable to "set[MyLiteral]"
Type parameter "_T@set" is invariant, but "type[int]" is not the same as "MyLiteral"
Consider switching from "set" to "Container" which is covariant (reportReturnType)
mypy output:
enumadd.py:12: note: Revealed type is "builtins.set[enumadd.MyEnumAB]"
enumadd.py:21: note: Revealed type is "builtins.set[Union[type[Literal[1]], type[Literal[2]]]]"