add option to use dataclasses instead of attrs in generated code #1158
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
The last time this idea came up (#743), @dbanty felt that there wasn't a compelling reason to switch from
attrs
. I decided anyway to see how much of a lift it would be— in the generated code, that is, not in the generator. A few reasons:attrs
is very popular, I think it's likely to become somewhat less of a standard as Python's dataclasses module keeps on copying features from it.attrs
has some features thatdataclasses
doesn't, but we're not really using those features anyway in the generated code (with one exception that I'll mention below). Mostly we're just using the simplest possible attribute declaration pattern in model classes.As I expected, implementing this for the model classes was pretty simple. The only other place we were using
attrs
in the generated code was in theClient
andAuthenticatedClient
classes, and there things got trickier.In those classes, we were taking advantage of
attrs
'salias
option in order to define underscored attributes that the app isn't meant to access directly, but that can still be set by name without the underscore in the initializer. You can't do that with dataclasses. However, since the app isn't meant to access them directly, I felt freer to change things there... and attrs/dataclass-type behavior is not really inherent to what the client classes are for, from the app's point of view, it's just an implementation detail.So, in
use_dataclasses
mode, I changed the clients to plain Python classes with no attrs/dataclass decorators—and moved those Httpx-related attributes into a separate dataclass, so we could still take advantage of copy-and-set behavior for builder methods. That is a fairly different implementation and code structure, which makes the Jinja template a bit hairy, but you can see what it ends up looking like here. However, when you're not inuse_dataclasses
mode, the implementation does not change at all (you can see there are no changes to existing code ingolden_record
), so I believe this is not a breaking change.(We could decide to unify those implementations by backporting those changes to the not-using-dataclasses mode, so the only differences between the two would be the decorator names. I do think that'd be a little bit cleaner— the Httpx options do all go together, and I don't think there's a compelling reason to have them be separate attributes on the client class. And, again, apps were never meant to access those directly... but in Python, we couldn't prevent that, so that could be considered a breaking change depending on your standards for what is a public/supported interface.)