ruamel.yaml.representer.RepresenterError: cannot represent an object: {'value': }
Asked Answered
T

1

2

For Python 3.7, I am getting following error:

 `ruamel.yaml.representer.RepresenterError: cannot represent an object: {'a': 3}`

For the following piece of code taken from answer for PyYAML - Saving data to .yaml files. How can I fix this error?

from ruamel.yaml import YAML

class Config(dict):
    def __init__(self, filename, auto_dump=True):
        self.filename = filename
        self.auto_dump = auto_dump
        self.changed = False
        self.yaml = YAML()
        self.yaml.preserve_quotes = True
        # uncomment and adapt to your specific indentation
        # self.yaml.indent(mapping=4, sequence=4, offset=2)
        if os.path.isfile(filename):
            with open(filename) as f:
                # use super here to avoid unnecessary write
                super(Config, self).update(self.yaml.load(f) or {})

    def dump(self, force=False):
        if not self.changed and not force:
            return
        with open(self.filename, "w") as f:
            self.yaml.dump(self, f)
        self.changed = False

    # following methods unchanged from PyYAML example
    def updated(self):
        if self.auto_dump:
            self.dump(force=True)
        else:
            self.changed = True

    def __setitem__(self, key, value):
        super(Config, self).__setitem__(key, value)
        self.updated()

    def __delitem__(self, key):
        super(Config, self).__delitem__(key)
        self.updated()

    def update(self, kwargs):
        super(Config, self).update(kwargs)
        self.updated()


cfg = Config("test.yaml")
print(cfg)
cfg['a'] = 3  # <=Error occurs
print(cfg)
cfg.update({"b": 4})
cfg.update(c=5)
del cfg['a']
print(cfg)

Related:

Thigmotaxis answered 6/8, 2021 at 8:49 Comment(0)
A
2

It looks like the code in "PyYAML - Saving data to .yaml files" was not tested, normally there would be some output (which is automatically included in the answers I post).

The code almost works, but needs a cast of self to dict to get the key-value pairs, otherwise ruamel.yaml tries to dump the attributes (.filename, etc).

If you want both (dict-like) arguments as well as key-value arguments for .update() you'll need to extend it argument list:

import os
from ruamel.yaml import YAML

class Config(dict):
    def __init__(self, filename, auto_dump=True):
        self.filename = filename
        self.auto_dump = auto_dump
        self.changed = False
        self.yaml = YAML()
        self.yaml.preserve_quotes = True
        # uncomment and adapt to your specific indentation
        # self.yaml.indent(mapping=4, sequence=4, offset=2)
        if os.path.isfile(filename):
            with open(filename) as f:
                # use super here to avoid unnecessary write
                super(Config, self).update(self.yaml.load(f) or {})

    def dump(self, force=False):
        if not self.changed and not force:
            return
        with open(self.filename, "w") as f:
            self.yaml.dump(dict(self), f)
        self.changed = False

    # following methods unchanged from PyYAML example
    def updated(self):
        if self.auto_dump:
            self.dump(force=True)
        else:
            self.changed = True

    def __setitem__(self, key, value):
        super(Config, self).__setitem__(key, value)
        self.updated()

    def __delitem__(self, key):
        super(Config, self).__delitem__(key)
        self.updated()

    def update(self, *args, **kw):
        for arg in args:
            super(Config, self).update(arg)
        super(Config, self).update(**kw)
        self.updated()


cfg = Config("test.yaml")
print(cfg)
cfg['a'] = 3  # <=Error occurs
print(cfg)
cfg.update({"b": 4})
cfg.update(c=5)
del cfg['a']
print(cfg)

print('------')
print(open(cfg.filename).read())

which gives:

{}
{'a': 3}
{'b': 4, 'c': 5}
------
b: 4
c: 5

This dumps the config as if it were a dict and there is no tag in the YAML to indicate what has been dumped and nothing would help identifying during reading back of the configuration. So it would IMO be better to make this a dumpable class in the normal way and dump with a tag like !Config.

Askance answered 6/8, 2021 at 18:2 Comment(5)
Thank you. Would it be possible to apply your solution (auto dumping) for changes in nested dict ex: my_dict[in_key][out_key] = 100, is locally changed but is not saved into data? Please see: #68691990Thigmotaxis
Instead of self.yaml.dump, can we use self.yaml.safe_dump?Thigmotaxis
No we cannot use self.yaml.safe_dump as self.yaml is an instance of YAML and that has no safe_dump method (or attribute). Did you read the docs? Did you find the typ argument to YAML? ( self.yaml = YAML(typ='safe') will get you the C based safe loader)Askance
Do you advice to use pure=True as well along with typ='safe'?Thigmotaxis
Not necessarily, there are differences between the pure Python and the C implementation, but I don't think you'll notice for a config file.Askance

© 2022 - 2024 — McMap. All rights reserved.