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 does not recognize aliases of dataclasses.dataclass #5383
$ mypy mypy-test.py
mypy-test.py:22: error: Unexpected keyword argument "arg1" for "B"
mypy-test.py:23: error: Unexpected keyword argument "arg1" for "C"
mypy-test.py:24: error: Unexpected keyword argument "arg1" for "D"
Notice that mypy has no trouble recognizing the signature of A's constructor. I can understand how mypy would have a hard time with dataclass_wrapper, and dataclass_alias is probably not critical in terms of use case. However, dataclass_alias2 is important if you want (as I do) to define many data classes with the same options, especially if you want to make these options available as part of your module's public interface.
It's unlikely that mypy will support dataclass_wrapper, but dataclass_alias and dataclass_alias2 are something that mypy could support. This is low priority since adding support for these use cases would require some pretty non-trivial new machinery. Also, dataclasses is still new and we don't know how common this use case is. We can increase the priority if many users encounter this limitation.
Reacted by William Schwartz, Buck Evan and Neil Girdhar
Does there not exist any annotation or cast that will tell mypy to treat some variable as if it were dataclasses.dataclass ? I had expected typing.cast to do the trick, but apparently there's some magic happening here that doesn't involve the type system -- the type of dataclass is simply Callable.
Here's some of my attempts, with corresponding errors:
demo.py:
import dataclasses
immutable = dataclasses.dataclass(frozen=True, order=True)
@immutable
class MyClass:
myint: int
myobject = MyClass(3)
print(myobject.myint)
$ mypy demo.py
demo.py:8: error: Too many arguments for "MyClass"
Next is my attempt to use annotations to request that mypy treat immutable as dataclass. This won't be perfectly correct, but still much preferable to the above behavior. To my eye, it actually seems to almost work. The necessary changes would be to allow dataclasses.dataclass? to be a valid type, and also to have the the corresponding mypy dataclass plugin act on it.
immutable: dataclasses.dataclass = dataclasses.dataclass(frozen=True, order=True)
demo.py:3: error: Function "dataclasses.dataclass" is not valid as a type
demo.py:3: note: Perhaps you need "Callable[...]" or a callback protocol?
demo.py:6: error: dataclasses.dataclass? not callable
demo.py:9: error: Too many arguments for "MyClass"
Using cast rather than an annotation actually produces the exact same errors:
immutable = typing.cast(dataclasses.dataclass, dataclasses.dataclass(frozen=True, order=True))
demo.py:4: error: Function "dataclasses.dataclass" is not valid as a type
demo.py:4: note: Perhaps you need "Callable[...]" or a callback protocol?
demo.py:7: error: dataclasses.dataclass? not callable
demo.py:10: error: Too many arguments for "MyClass"
From my perspective, the problem here is that the special-case handling for dataclasses.dataclass isn't attached to its type. What is it in fact attached to? Its name? I don't know, but I expect it's the name. Adding one level of abstraction would fix the problem, I believe: define a type for dataclass (I'd name it DataclassMeta) and have the mypy plugin act on anything with that type. Then other objects (not just the one stdlib object) can have the behavior of dataclass.
P.S. I hope my use case isn't relevant, but:
My intent is to ease the use of immutable-by-default design in my team by making a clean alias of dataclasses.dataclass(frozen=True, order=True) -- otherwise, the "good" code looks worse than the "worse".
To me, this improvement seems much too specific to dataclass. I'd rather see a general solution that works for enum.unique, functools.total_ordering and the rest.
I think the Right Way to fix this is dataclass() should return something more specific than Callable, and mypy plugins should be prevented from seeing the name of variables, seeing only the types. Then some (most?) of my attempts above would Just Work.
I would like this too, but it might have been easier if there were a dataclass base class (say, DataClass) in the standard library that applies dataclass in its __init_subclass__. Then mypy could just check for subclasses of DataClass) and custom subclasses would work fine.
The dataclass transforms PEP (681) would be a great addition to MyPy 😄 It would solve this problem, and the problem of base classes that define dataclasses.
Perhaps this issue should be renamed "Implement PEP 681" to give it a bit more visibility? It's a huge deal for projects like Flax that extensively use dataclasses (both using a modified decorator flax.struct.dataclass and a special base class flax.linen.Module).
Reacted by Robert Schweizer, Efrem Rensi, Katelyn Gigante, Daniel Miranda and Kale-ab Tessera
If you need something that is truly, exactly a dataclass alias, you can do something like from dataclasses import dataclass as dataclass_alias (instead of assignment, possibly also mix in an if TYPE_CHECKING) and mypy will do the right thing
Activity
JukkaL commentedon Jul 24, 2018
It's unlikely that mypy will support
dataclass_wrapper, butdataclass_aliasanddataclass_alias2are something that mypy could support. This is low priority since adding support for these use cases would require some pretty non-trivial new machinery. Also,dataclassesis still new and we don't know how common this use case is. We can increase the priority if many users encounter this limitation.wkschwartz commentedon Jul 24, 2018
In the mean time, perhaps a single sentence added to the documentation might be helpful.
gvanrossum commentedon Jul 24, 2018
@wkschwartz
That makes sense. Since you know where you (would have) looked in the docs, can you help us by sending a Pull Request?
Refs python#5383: Document that aliasing dataclass fails
Refs #5383: Document that aliasing dataclass fails (#5387)
edaqa-uncountable commentedon Apr 29, 2021
Support for the
dataclass_wrappercase would be helpful. I was trying to create a wrapped class that adds API information to my dataclasses.The workaround I've resorted too is double-wrapping:
I'd also be wrapping the fields in
my_fieldto provide a similarly simplified interface.bukzor commentedon Sep 23, 2021
Does there not exist any annotation or cast that will tell mypy to treat some variable as if it were
dataclasses.dataclass? I had expectedtyping.castto do the trick, but apparently there's some magic happening here that doesn't involve the type system -- the type ofdataclassis simplyCallable.Here's some of my attempts, with corresponding errors:
demo.py:Next is my attempt to use annotations to request that mypy treat
immutableasdataclass. This won't be perfectly correct, but still much preferable to the above behavior. To my eye, it actually seems to almost work. The necessary changes would be to allowdataclasses.dataclass?to be a valid type, and also to have the the corresponding mypy dataclass plugin act on it.Using cast rather than an annotation actually produces the exact same errors:
From my perspective, the problem here is that the special-case handling for dataclasses.dataclass isn't attached to its type. What is it in fact attached to? Its name? I don't know, but I expect it's the name. Adding one level of abstraction would fix the problem, I believe: define a type for
dataclass(I'd name it DataclassMeta) and have the mypy plugin act on anything with that type. Then other objects (not just the one stdlib object) can have the behavior ofdataclass.P.S. I hope my use case isn't relevant, but:
My intent is to ease the use of immutable-by-default design in my team by making a clean alias of
dataclasses.dataclass(frozen=True, order=True)-- otherwise, the "good" code looks worse than the "worse".gvanrossum commentedon Sep 23, 2021
If you need help figuring this out today, I recommend asking in the typing discussions group: https://github.com/python/typing/discussions
parched commentedon Nov 19, 2021
If this proposal was implemented I think you'd be able to do something like this
which would be neat.
bukzor commentedon Nov 19, 2021
To me, this improvement seems much too specific to
dataclass. I'd rather see a general solution that works forenum.unique,functools.total_orderingand the rest.I think the Right Way to fix this is
dataclass()should return something more specific than Callable, and mypy plugins should be prevented from seeing the name of variables, seeing only the types. Then some (most?) of my attempts above would Just Work.NeilGirdhar commentedon Nov 21, 2021
I would like this too, but it might have been easier if there were a
dataclassbase class (say,DataClass) in the standard library that applies dataclass in its__init_subclass__. Thenmypycould just check for subclasses ofDataClass) and custom subclasses would work fine.NeilGirdhar commentedon Nov 21, 2021
I think I just got this working by adding a custom mypy plugin like this:
NeilGirdhar commentedon Jan 24, 2022
The dataclass transforms PEP (681) would be a great addition to MyPy 😄 It would solve this problem, and the problem of base classes that define dataclasses.
NeilGirdhar commentedon Mar 2, 2022
Perhaps this issue should be renamed "Implement PEP 681" to give it a bit more visibility? It's a huge deal for projects like Flax that extensively use dataclasses (both using a modified decorator
flax.struct.dataclassand a special base classflax.linen.Module).hauntsaninja commentedon Aug 24, 2023
Use PEP 681, which is implemented.
If you need something that is truly, exactly a dataclass alias, you can do something like
from dataclasses import dataclass as dataclass_alias(instead of assignment, possibly also mix in anif TYPE_CHECKING) and mypy will do the right thing