-
-
Notifications
You must be signed in to change notification settings - Fork 50
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Nested attrs.define
dataclasses not serialized correctly when a subfield is also an attrs.define
dataclass marked with attrs.field
#643
Conversation
- an edge case that is not handled is when nesting `attrs.define` dataclasses where a subfield is marked with `attrs.field` - this would typically happen when using a default factory for this field or with custom validation - the code fix checks if `attrs.asdict` is both available and appropriate to use for serializing a dataclass-like object
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for contributing! Nested attrs defines certainly makes sense to be supported.
I added a few comments. Also, do you know why your pull request did not run the github workflows? I can't really merge if I am unable to see everything run.
Figured out why tests were not being run. Github has a new "merge experience" which I had active. Apparently that doesn't have button to approve runs for new contributors. |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #643 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 22 22
Lines 6499 6504 +5
=========================================
+ Hits 6499 6504 +5 ☔ View full report in Codecov by Sentry. |
additionally fixed `test_nested_without_default` to use the correct `attrs` model in the test
Hi, thanks for responding and taking a look at this. I believe that I have made the changes you requested |
Also, I am not sure why 2 of the tests are failing, since the error messages aren't that helpful |
Don't worry about that. It is not related to your changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for contributing!
def test_nested_without_default(self, parser): | ||
parser.add_argument("--data", type=AttrsWithNestedDataclassNoDefault) | ||
cfg = parser.parse_args(["--data.p1=1.23"]) | ||
assert cfg.data == Namespace(p1=1.23, subfield=Namespace(p1="-", p2=0)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks somewhat unexpected. I would have guessed that the parsed value would be Namespace(p1=1.23, subfield=None)
. But anyway, this is not related to this pull request so I would say to keep it like this for now. Probably this behavior will need to change for #287.
What does this PR do?
I am trying to see if I can convert a bunch of internal
dataclasses.dataclass
config objects to be defined withattrs.define
instead for field validation and conversion.I've noticed that
jsonargparse
handles simple cases withattrs
-style dataclasses, but it breaks down with nestedattrs
-style dataclasses ONLY when the subfield is marked with anattrs.field
descriptor, such as when using a default factory.Here is a simple example:
which leads to this call stack:
Thus, it would appear that the only change is needed in
jsonargparse._signatures.dataclass_to_dict
. More specifically, this pull request does the following in terms of code changes:pydantic
dataclass, it will check if theattrs
library is available using the flag already computed injsonargparse._optional
attrs
is available, then it will check if the input dataclass-like object is anattrs.define
-style dataclass.attrs.asdict
to serialize the model instead ofdataclasses.asdict
Alternatives
There are several alternatives to implementing this pull request that all fall short in some way.
1.
jsonargparse.lazy_instance
This makes the
attrs.define
-style dataclass work withjsonargparse
and is possibly the simplest alternative, but it does NOT allow creating an instance with no init args:which is not desired when these dataclasses are not just intermediates between command-line inputs and the rest of the code base.
2. Don't make the subfields have default values
This is similar to the above in that
jsonargparse
can handle this case and will correctly see thatSubField
has default values. However, this has the same problem that you cannot create a defaultArgs
object without init values. There is a further complication with field order when introducing required values.3. Make use of
attrs.field
convertersThis technically works on the code end for constructing default values and when using
jsonargparse.CLI
, but the fields on theSubField
are not shown in the CLI help page, which is not ideal.4. Don't nest
attrs.define
-style dataclassesThis would obviously solve the problems without code changes, but considering that nested
dataclasses.dataclass
objects are handled AND this lib should not impose that kind of design decision on users, this is not really that great of a choice. Further, the required changes are extremely minimal.Before submitting
v4.35.0
since I only tested with the latest available releasev4.34.1