Suggestion: Consider changing the order for variable initialization in `__init__`
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 5/5
- Estimated time
- Over a week
- Newbie friendliness
- 25/100
Research direction
Start by reading the documentation section describing default factories and the generated init behavior. Then trace how attrs generates initialization for fields with supplied values, defaults, and factories, and check whether tests cover factory ordering or the NOTHING sentinel. Done means the proposed ordering is evaluated with tests and the supported behavior is documented or declined.
Written by the indexing model from the issue text.
Description
First of all thanks a lot for the awesome library! I just recently discovered it and it saved me so many headaches. Recently I was trying to do something of this sort, where either x or y has to be given to the __init__ method for this to be valid:
@define
class MyClass:
x: int = field()
y: int = field()
@x.default
def y_plus_one(self):
return self.y + 1
@y.default
def x_plus_one(self):
return self.x + 1
This however (as the docs state) fails because self.y would not be initialized during the call to y_plus_one. Even though the docs state this fails I wanted to try and fix the issue and managed to do so in a very hacky way. However in the process I thought up a non invasive way in which this may work.
If we first initialize those fields that were given a value through __init__ and then use the NOTHING sentinel to initialize the values for those attributes that were not initialized through __init__ but before calling the factories, the problem dissapears. The reordered __init__ method would look something like this (I'm not really sure how the method is autogenerated but its a rough idea):
@define
class MyClass:
...
def __init__(self, x = NOTHING, y = NOTHING): # <- this is autogenerated
# initialize all fields before calling factories
if x is not NOTHING:
self.x = x
elif isinstance(self.__attrs_attrs__['x'].default, Factory):
self.x = NOTHING
elif self.__attrs_attrs__['x'].default is not None:
self.x = self.__attrs_attrs__['x'].default
if y is not NOTHING:
self.y = y
elif isinstance(self.__attrs_attrs__['y'].default, Factory):
self.y = NOTHING
elif self.__attrs_attrs__['y'].default is not None:
self.y = self.__attrs_attrs__['y'].default
# call the factories for all fields that were not given a value through init
if self.x is NOTHING and isinstance(self.__attrs_attrs__['x'].default, Factory):
self.x = self.__attrs_attrs__['x'].default.factory(self)
if self.x is NOTHING:
raise ValueError("a factory may not return the NOTHING sentinel")
if self.y is NOTHING and isinstance(self.__attrs_attrs__['y'].default, Factory):
self.y = self.__attrs_attrs__['y'].default.factory(self)
if self.y is NOTHING:
raise ValueError("a factory may not return the NOTHING sentinel")
...
This has the additional benefit that now I can throw more descriptive error messages during initialization, like:
...
@x.default
def y_plus_one(self):
if self.y is NOTHING:
raise ValueError("either x or y has to be initialized")
return self.y + 1
...
- Dominant language
- Python
- Stars
- 5.8k
- Forks
- 490
- Avg merge
- 3d 12h
- Merged PRs (30d)
- 3
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing 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.
More from python-attrs/attrs
-
Docs: `attrs.filters` is missing stated examplesPossibly taken @feiiiiii5 claimed this 9 days ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
python-attrs/attrs#1627 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 68/100
python-attrs/attrs#1637 ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 20/100
python-attrs/attrs#1620 ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 55/100
python-attrs/attrs#1596 · 2 comments · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
python-attrs/attrs#1549 · 3 comments ·
Maintainers usually reply within 1 day
All issues in python-attrs/attrs
Similar issues
-
namespace operations
Difficulty 1/5 Under an hour Newbie friendliness 72/100
EclipseFdn/open-vsx.org#13737 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
zhuima/awesome-cloudflare#237 ·
-
Zero-token evaluations are treated as missing cost in selectionPossibly taken @sylvesterkaczmarek claimed this today. Open
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
google-research/rrsi#6 ·
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
aws-samples/sample-aws-genai-db-modernizer#294 ·
Maintainers usually reply within 1 day
-
feedback simulation workshop
Difficulty 2/5 1-3 hours Newbie friendliness 84/100
githubnext/gh-aw-workshop#4174 ·
Maintainers usually reply within 1 day