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
{{ message }}
Repository navigation
mypy 0.990 breaks commonly used Protocol definition for dataclasses #14029
With mypy 0.990 the dataclass __dataclass_fields__ attribute is now a ClassVar, which mypy considers to be incompatible with an instance attribute. This causes results like:
error: Incompatible types in assignment (expression has type "MyDataclass", variable has type "Dataclass") [assignment]
note: Protocol member Dataclass.__dataclass_fields__ expected instance variable, got class variable
Was this change intentional, do all users of this trick have to change __dataclass_fields__: dict to ClassVar[dict], or is this an unintended result?
classDataclass(Protocol):
__dataclass_fields__: dict@dataclassclassMyDataclass:
blah: intx: Dataclass=MyDataclass(blah=123)
# ^ error: Incompatible types in assignment (expression has type "MyDataclass", variable has type "Dataclass") [assignment]# note: Protocol member Dataclass.__dataclass_fields__ expected instance variable, got class variable
Expected Behavior
I'm not sure to be honest whether the new behavior is correct or not, wanted to make sure.
classDataclass(Protocol):
__dataclass_fields__: dictT=TypeVar("T", bound=Dataclass)
@dataclassclassMyDataclass:
blah: int#### Example 2classDataclassSerializer(Generic[T]):
...
classMySerializer(DataclassSerializer[MyDataclass]):
# ^ error: Type argument "MyDataclass" of "Serializer" must be a subtype of "Dataclass" [type-var]pass
I think it's correct, and you'll need to add ClassVar. mypy recently started allowing classes as protocol implementations, which you'll probably want to distinguish. See #4536 (comment) which is the reason why I made the change.
I think the change makes sense and it's more logical to treat __dataclass_fields__ as a ClassVar, but it kinda sucks that previous versions of mypy don't accept a protocol with it being a classvar. That means you can be either compatible with mypy pre-0.990, or post-0.990, but not with both. For applications it's probably not a big deal, but it's not great for libraries.
Activity
intgr commentedon Nov 7, 2022
Another related case:
https://mypy-play.net/?mypy=master&python=3.10&gist=04ece0675f41515ecf091ba1de914605
hauntsaninja commentedon Nov 7, 2022
I think it's correct, and you'll need to add ClassVar. mypy recently started allowing classes as protocol implementations, which you'll probably want to distinguish. See #4536 (comment) which is the reason why I made the change.
oxan commentedon Nov 7, 2022
I think the change makes sense and it's more logical to treat
__dataclass_fields__as a ClassVar, but it kinda sucks that previous versions of mypy don't accept a protocol with it being a classvar. That means you can be either compatible with mypy pre-0.990, or post-0.990, but not with both. For applications it's probably not a big deal, but it's not great for libraries.hauntsaninja commentedon Nov 7, 2022
oxan, could union of two protocols work for giving you a little bit more mypy compatibility?
oxan commentedon Nov 7, 2022
Ah yes, something like this seems to work:
Thanks!