Menu

#394 attrs and ruamel.yaml

open
nobody
None
minor
bug
2021-08-21
2021-08-21
ssph
No

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 …

Discussion

  • Anthon van der Neut

     
  • Anthon van der Neut

    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: *x
    should work in 0.17.12, but not tested beyond your example (and my recursive version of it)

     
  • ssph

    ssph - 2021-08-21

    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:

    import ruamel.yaml
    
    s = """
    a:
        b: !BClass
            c: 1
    """
    
    class BClass:
        def __init__(self):
            self.c = c
            self.c2 = c*2
    
    yaml = ruamel.yaml.YAML()
    yaml.register_class(BClass)
    yaml.load(s)
    y['a']['b'].c2
    

    or any other class relying on __init__().

    I also did not stumble upon this behaviour mentioned in the documentation. Have I missed it?

     
  • Anthon van der Neut

    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 key c2, or IMO better make c2 a property that calculates it when used (possible with cache).

     

Log in to post a comment.