python-attrs / python-attrs/attrs
Making third-party extensions a bit easier
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.8k
- Forks
- 480
- Avg merge
- 2h 15m
- Merged PRs (30d)
- 2
Description
I am researching how we can expand the field with more metadata on our project. The documentation was very helpful for getting started, but I've hit a few places where there is a bit of friction
Adding field decorators requires extending attr._make._CountingAttr
This is way more complicated then it seems at first glance because:
- the
_CountingAttrkeeps an internal counter for the ordering - changing the return type of
fieldmakes it be picked up as a customdefaultinstead of an extension of_CountingAttr
The initial design I considered was
def field(*, metadata=None, **kwargs: Any) -> Any:
if not metadata:
metadata = {}
metadata.setdefault("my_ext", MyMetadata())
return MyCountingAttr(attrs.field(**kwargs, metadata=metadata))
class MyCountingAttr(attr._make._CountingAttr):
def __init__(self, ca):
for f in ca.__slots__:
setattr(self, f, getattr(ca, f))
attr._make._CountingAttr.cls_counter -= 1
self.counter -= 1
def new_decorator(self, meth):
my_metadata: TmtAttrsMetadata = self.metadata["my_ext"]
my_metadata.func = meth
return meth
@attrs.define
class MyMetadata:
func: Callable[..., Any] | None = None
@attrs.define
class Example:
x: field()
@x.new_decorator
def _x_my_func(self):
pass
but this fails when it gets to
https://github.com/python-attrs/attrs/blob/f0e420b71af1a5cd5dbf43efd1a42aece6ce8f4e/src/attr/_make.py#L403-L407
Could not find a way around it besides changing that to a issubclass check
Many useful internal functions are not exposed
For example attr._make._determine_whether_to_implement would be really nice to not have to re-implement, especially when it comes to the correct handling of classmethod. Admittedly my usage there is quite weird (injecting some methods/classmethods based on inputs to the @define decorator) and it could be better handled with inheritance/metaclass, but it's the first example of the internal helpers that I've found in my code.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/attr/_make.py, especially the referenced _CountingAttr handling around lines 403-407 and _determine_whether_to_implement. Trace how field decorators and classmethod handling are currently recognized, then compare the extension patterns described in the issue. Done means proposing and validating a supported way to extend fields or expose the needed helpers, with maintainer agreement on the API and tests for the chosen behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- developer-experience
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100