"Missing required positional argument" for default field
fortierq opened this issue · 5 comments
Hello,
In the following code, I get: TypeError: init() missing 1 required positional argument: 'a'
from pyfields import autoclass, field
@autoclass
class A:
a: int = field(default = 1)
@autoclass
class B(A):
b = field()
B(b=3)
It works when I add a type hint to b (b : int = field()).
Is it a bug or a feature?
pyfields version: 1.6.0
Thanks @fortierq for opening this ! Indeed I am able to reproduce the issue.
It seems that the issue comes from the fact that I misunderstood how B.__annotations__
works: apparently when B
does not have any annotations of its own, this is set to th annotations of the parent(s). So it contains {'a': int}
, For this reason autofields
does not work correctly, as it does not assume inherited annotations: it recreates a definition for a
in B
, overriding the inherited one. When you add the type hint in B
, then B.__annotations__
does not contain the annotations from A
anymore, this is why it works. Tricky !
I need to investigate how to fix this, the key would be to find a reliable way to know when there are new annotations in a class, or if they are just the inherited ones. If you have an idea do not hesitate to suggest it here ! Note that it should support multiple inheritance with parent classes in any order, having annotations or not...
Thanks for your answer.
Not sure I understand the issue, but I am definitely interested by looking at the code when I find the time.
I like the flexibility of the default_factory option, which seems missing from dataclasses.
Not sure I understand the issue, but I am definitely interested by looking at the code when I find the time.
Well the issue is that in python, cls.__annotations__
is the official way to get the type annotations from a class, but apparently when the class does not define any, you get the annotations from one of the class parents. That was not the intuitive behaviour I was expecting from python, so my code was always assuming that when it finds some field in the annotations, it was something overridden in the class. So my code was finding that a
was overriden by B
.
Anyway I found a good way to do the check I was talking about here so that should now be easy to fix, I'll do it in the upcoming days. Thanks again for spotting this issue !
Note for reference: the bug was also happening with the shortcut autofields notation:
from pyfields import autoclass, field
@autoclass
class A:
a: int = 1
@autoclass
class B(A):
b = field()
B(b=3)
This should be fixed in 1.6.1, that will be available in a few minutes. Thanks again @fortierq !
Great! Thanks for your work.