I wanted to load an attr.s class, but noticed, that the default values were not set:
import attr
import ruamel.yaml
@attr.s()
class A:
yaml_tag = '!A'
a = attr.ib(init=True, kw_only=True)
b = attr.ib(init=True, kw_only=True, default=2)
s = """
- !A
a: 1
"""
yaml = ruamel.yaml.YAML()
yaml.register_class(A)
y = yaml.load(s)
print(y)
print(A(a=1))
The results are:
[A(a=1, b=NOTHING)]
A(a=1, b=2)
whereas I would expect:
[A(a=1, b=2)]
A(a=1, b=2)
That behaviour was already investigated by the good attrs people:
- https://github.com/python-attrs/attrs/issues/735
- https://github.com/python-attrs/attrs/issues/741
Is there already a way to initiate attr.s classes, so that their attributes have their default values? If not, do you think, it might be possible to add this feature? I could also live with an additional (optional) parameter init=True for the register_class() method …
It is of course not as simple, as some suggested in the links that are included, that you can replace calling
__new__with__init__. The init might have positional parameters (arguments), but more importantly I need the object before I can start parsing the subnodes as there might be recursion:- &x !A a: *xshould work in 0.17.12, but not tested beyond your example (and my recursive version of it)
Thanks for that really fast fix!! It works for my code which uses
attr.s, but I noticed, that it is not working for this:or any other class relying on
__init__().I also did not stumble upon this behaviour mentioned in the documentation. Have I missed it?
ruamel.yaml is not calling
_init__()and it shouldn't, it updates the attributes, If you have an__init__(arg, *, x=y)I would not know what to pass to arg. If you want your last line to work, you will need to include a keyc2, or IMO better makec2a property that calculates it when used (possible with cache).