Reputation: 3106
I have this nested dictionary class, whose instances I need to dump into YAML
class NestedDict(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
On dumping this dictionary:
pyaml.dump(nesteddict)
I get this error(only an excerpt of the entire message object posted):
"RepresenterError: cannot represent an object: {'a1401': 'ts755', 'ts64': {'topic': {'a1561': 'Process Control'}}, 'a1450': 'ts107', 'a1609': 'ts341', 'a1400': 'ts753', ......
So how to neatly represent this in YAML? I read that PyYAML does support nested recursive structures.
Upvotes: 3
Views: 2703
Reputation: 76578
YAML does support nested recursive structures:
import ruamel.yaml
data = [1, 3]
data.append(data)
print ruamel.yaml.dump(data)
Will give you YAML with an anchor (&id001
) and a reference (*id001
):
&id001
- 1
- 3
- *id001
And your simple derivative of a dict
can be dumped, at least with ruamel.yaml without a problem as well¹:
import ruamel.yaml
class NestedDict(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
data = NestedDict(a=1, b=2)
data['c'] = data
print ruamel.yaml.dump(data)
This gives you:
&id001 !!python/object/new:__main__.NestedDict
dictitems:
a: 1
b: 2
c: *id001
If you need a more complex representation, e.g. filter out some
dict values, you have to tell ruamel.yaml how to represent your objects.
To tell it that NestedDict has a representer you can either make it a subclass of ruamel.yaml.YAMLObject
, provide a class attribute yaml_tag = "!NestedDict"
and implement __repr__()
; or you can provide an explicit representer.
The latter is what is internally used and IMO somewhat easier to implement as you can just piggy-back on the dictionary code by having that return a dictionary representation (i.e top level key-value pairs) of your object.
def nested_dict_representer(dumper, node):
return dumper.represent_mapping("!NestedDict", xyz)
Where xyz
is some key-value pair representation of your object.
¹ Disclaimer: I am the author of that package, which is an enhanced version of PyYAML.
Upvotes: 2