Suppose I have the following:
from collections import OrderedDict
from dataclasses import dataclass
@dataclass
class HelloWorld:
x: OrderedDict[str, int]
a = OrderedDict([("a", 0), ("c", 2), ("b", 1)])
HelloWorld(a) <--- # type error here
The type error produced is:
Argument of type "OrderedDict[Literal['a', 'c', 'b'], Literal[0, 2, 1]]" cannot be assigned to parameter "x" of type "OrderedDict[str, int]" in function "__init__"
"OrderedDict[Literal['a', 'c', 'b'], Literal[0, 2, 1]]" is incompatible with "OrderedDict[str, int]"
Type parameter "_KT@OrderedDict" is invariant, but "Literal['a', 'c', 'b']" is not the same as "str"
Type parameter "_VT@OrderedDict" is invariant, but "Literal[0, 2, 1]" is not the same as "int
Oddly enough, this very similar snippet does not produce an error:
from collections import OrderedDict
from dataclasses import dataclass
@dataclass
class HelloWorld:
x: OrderedDict[str, int]
HelloWorld(OrderedDict([("a", 0), ("c", 2), ("b", 1)])) # <--- no error
cast
is often a viable solution, but here you can just annotate the initial variable. That will preserve the type safety of your code (unlike cast
which can cast a str
to dict[int, int]
equally well). Pyright should have not complain about the following:
from collections import OrderedDict
from dataclasses import dataclass
@dataclass
class HelloWorld:
x: OrderedDict[str, int]
a: OrderedDict[str, int] = OrderedDict([("a", 0), ("c", 2), ("b", 1)])
HelloWorld(x=a)
And here's a playground.
This error is caused by overly optimistic inference of pyright
together with OrderedDict
invariance (as any MutableMapping
).
As @InSync noticed in comments, on Python 3.7 and above you can build OrderedDict from a dict literal still preserving the order, and inference is less specific in that case:
a = OrderedDict({"a": 0, "c": 2, "b": 1})
HelloWorld(x=a)