Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork411
Addreuse() toAttribute for field evolution#1429
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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
base:main
Are you sure you want to change the base?
Conversation
with additional `inherited` kwarg to preserve inherited class order
for more information, seehttps://pre-commit.ci
Tinche commentedMay 2, 2025
Why does it need to be |
redruin1 commentedMay 5, 2025
If the goal is to reduce function chains, then how about the keyword classA:x=attrs.fields(Example).x.reuse()y=attrs.fields(Example).y.reuse(default="whatever")_z=attrs.fields(OtherExample).a.reuse(alias="z") |
Tinche commentedMay 5, 2025
I like it! |
redruin1 commentedMay 7, 2025
What exactly should I annotate for mypy? I notice that neither the return result of Line 311 in755b177
Should I just try to annotate everything this new feature touches? The contribution guidelines are a bit sparse in this regard. |
* Added material in "Other goodies" section in `examples.md`* docstrings for `field`, `attrib`, and `reuse`*Added towncrier changelog message
for more information, seehttps://pre-commit.ci
to_field() toAttributereuse() toAttribute for field evolutionhynek commentedJul 27, 2025
So I'm kinda OK with saying that you have to redefine your types, otherwise it gets hairy with ordering anyways (or some magic helper type, e.g., But how could any of this be made type-safe? |
Tinche commentedJul 27, 2025
We could contribute work to the mypy plugin so it would work 😇 |
redruin1 commentedJul 28, 2025
This would make sense. The only reason it is omitted in this particular implementation is because the type is already inherited from the
This is not a bad idea. If I understand you correctly, does that make the proposed syntax: @attrs.defineclassA:x:int=10y:str=attrs.field(default="blah")@attrs.defineclassB:z:dict= {"test":"result"}@attrs.defineclassChild(B,A):x:Annotated[Inherited(attrs.fields(A).x,default=20)]# Preserve parent orderingy:str=attrs.fields(A).y.reuse()# Add to end after inheritedz:Annotated[Inherited(attrs.fields(B).z,factory=dict)]# Preserve parent orderingassert"Child(x=20, z={}, y='blah')"==repr(Child()) It seems the question of what order to put inherited fields in is not trivial. I suppose you could argue that if you need absolute control of field order, then you should create an entirely composite class using
I'll look into this. I assume you're referring tothis? |
Uh oh!
There was an error while loading.Please reload this page.
Summary
Preliminary implementation of "evolving" existing
Attributeinstances back into_CountingAttrinstances, so that users may (easily) reuse attribute definitions from alreadydefined classes. Shouldresolve#637,#698,#829,#876,#946, and#1424.Usage:
This syntax is verbose, but least magical. And because you manually specify which class you want to pull attributes from, inheritance is not required; you can compose new classes entirely from parts of existing classes regardless of structure:
Utility methods like
attrs.make_class()and thethesekwarg inattrs.define()also work as you would expect.One potential pain point with a simple implementation of this feature is inherited attributes being reordered when redefined in this manner:
In my opinion, this behavior is a failure of the implementation, as it is reasonable to expect users to want to preserve this ordering, as in a worst-case scenario it can lead to non-constructable classes. This PR implements a new bool keyword argument
inheritedtofield, which tells attrs to use the ordering of the field in the parent class as opposed to adding to the end:Criticisms of this
inheritedkeyword are welcome, as I'm not convinced it is the best solution. However, I do think this functionality needs to be present in attrs in order to make this kind of attribute evolution a tenable approach.Pull Request Check List
mainbranch –use a separate branch!.pyi).tests/typing_example.py.attr/__init__.pyi, they'vealso been re-imported inattrs/__init__.pyi.docs/api.rstby hand.@attr.s()and@attrs.define()have to be added by hand too.versionadded,versionchanged, ordeprecateddirectives.The next version is the second number in the current release + 1.
The first number represents the current year.
So if the current version on PyPI is 22.2.0, the next version is gonna be 22.3.0.
If the next version is the first in the new year, it'll be 23.1.0.
attrs.define()andattr.s(), you have to add version directives to both..rstand.mdfiles is written usingsemantic newlines.changelog.d.