How to create a custom yaml mapping dumper for ruamel.yaml?

后端 未结 1 1900
失恋的感觉
失恋的感觉 2021-01-14 04:40

I\'m trying to make a custom YAML dumper/loader for some configuration objects. For simplicity, assuming we want to dump a object of class Hero to a hero.

相关标签:
1条回答
  • 2021-01-14 05:18

    The defintion for the RoundTripConstructor.construct_mapping is::

    def construct_mapping(self, node, maptyp=None, deep=False)
    

    and it needs to know what kind of mapping it is expected to construct. There is some expectation in the RoundTripDumper on what can be attached to such an object, so you best of emulating what the routines in the RoundTripDumper pass: CommentedMap (a normal dict is not going to work).

    So you will need to do something like:

    from ruamel.yaml import YAML
    from ruamel.yaml.comments import CommentedMap
    
    yaml = YAML()
    
    class Hero:
        yaml_tag = '!Hero'
        def __init__(self, name, age):
            self.name = name
            self.age = age
    
        @classmethod
        def to_yaml(cls, representer, data):
            return representer.represent_mapping(cls.yaml_tag,
                                                 {'name': data.name, 'age': data.age})
    
        @classmethod
        def from_yaml(cls, constructor, node):
            data = CommentedMap()
            constructor.construct_mapping(node, data, deep=True)
            return cls(**data)
    
        def __str__(self):
            return "Hero(name -> {}, age -> {})".format(self.name, self.age)
    
    
    yaml.register_class(Hero)
    
    ante_hero = Hero('Saber', 15)
    with open('config.yml', 'w') as fout:
        yaml.dump(ante_hero, fout)
    
    with open('config.yml') as fin:
        post_hero = yaml.load(fin)
    
    print(post_hero)
    

    which gives:

    Hero(name -> Saber, age -> 15)
    

    The above works because your class is relatively simple, if it could have recursive parts, you would need to follow a two-step creation process, with initial yield of the object created, so that it can be used during the recursion.

    That the maptyp defaults to None is historical, it must be set. E.g. one of the first things that construct_mapping does is trying to attach comments (if any were available on the node). I'll remove the default value in 0.15.55, which gives a more sensible error if you leave it out, like you did.

    0 讨论(0)
提交回复
热议问题