import yaml from peeringdb import get_backend from peeringdb.util import FieldGroups # from peeringdb.debug import try_or_debug # Wrap orm object into node for graph traversal class YamlWrap(FieldGroups): def __init__(self, o, depth): self.tag = 'tag:yaml.org,2002:map' self.object = o self.depth = depth self.fields = FieldGroups(o.__class__) @staticmethod def _resolve_one(name, value, depth): if depth > 0: return YamlWrap(value, depth - 1) else: return value.id @staticmethod def _resolve_many(name, value, depth): if depth > 1: return [YamlWrap(o, depth - 1) for o in value.all()] elif depth == 1: return list(value.values_list('id', flat=True)) def resolve(self, group, name, value): if group == 'scalars': return value elif group == 'one_refs': return YamlWrap._resolve_one(name, value, self.depth) elif group == 'many_refs': return YamlWrap._resolve_many(name, value, self.depth) else: raise ValueError(group) def field_values(self): for group in self.fields.GROUPS: if self.depth == 0 and group == 'many_refs': continue for name in self.fields[group]: value = self.resolve(group, name, getattr(self.object, name)) yield name, value def represent_wrapped(dumper, wrap): _dict = {} for name, value in wrap.field_values(): _dict[name] = value alist = [(k, _dict[k]) for k in sorted(_dict)] return dumper.represent_mapping(wrap.tag, alist) def default_representer(dumper, data): # Py2 workaround rep_func = getattr(dumper, 'represent_unicode', None) if rep_func is None: rep_func = dumper.represent_str return rep_func(str(data)) def _init(): dumper = yaml.SafeDumper for cls in get_backend().CUSTOM_FIELDS: dumper.add_representer(cls, default_representer) dumper.add_representer(YamlWrap, represent_wrapped) def dump(obj, depth, file): _init() if get_backend().is_concrete(type(obj)): obj = YamlWrap(obj, depth) yaml.safe_dump(obj, stream=file, default_flow_style=False)