From e2b27b619f20097df11bc133c6d6f8ceb8578e53 Mon Sep 17 00:00:00 2001 From: Tony Garnock-Jones Date: Mon, 16 Aug 2021 11:38:44 -0400 Subject: [PATCH] Schema encode --- implementations/python/preserves/schema.py | 53 ++++++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/implementations/python/preserves/schema.py b/implementations/python/preserves/schema.py index 08576ce..a53af8c 100644 --- a/implementations/python/preserves/schema.py +++ b/implementations/python/preserves/schema.py @@ -176,11 +176,14 @@ class Enumeration(SchemaEntity): def _encode(self): raise TypeError('Cannot encode instance of Enumeration') +def safeattrname(k): + return k + '_' if keyword.iskeyword(k) else k + def safesetattr(o, k, v): - if keyword.iskeyword(k): - setattr(o, k + '_', v) - else: - setattr(o, k, v) + setattr(o, safeattrname(k), v) + +def safegetattr(o, k): + return getattr(o, safeattrname(k)) class Definition(SchemaEntity): EMPTY = False @@ -255,7 +258,13 @@ class Definition(SchemaEntity): return None def _encode(self): - raise NotImplementedError('Not yet implemented') + if self.SIMPLE: + if self.EMPTY: + return encode(self.SCHEMA, ()) + else: + return encode(self.SCHEMA, self.value) + else: + return encode(self.SCHEMA, self) def _as_dict(self): return dict((k, getattr(self, k)) for k in self.FIELD_NAMES) @@ -266,6 +275,35 @@ class Definition(SchemaEntity): def __setitem__(self, name, value): return safesetattr(self, name, value) +def encode(p, v): + if p == ANY: + return v + if p.key == NAMED: + return encode(p[1], safegetattr(v, p[0].name)) + if p.key == ATOM: + return v + if p.key == EMBEDDED: + return v ## TODO: reconsider representation of embedded values? + if p.key == LIT: + return p[0] + if p.key == SEQOF: + return tuple(encode(p[0], w) for w in v) + if p.key == SETOF: + return set(encode(p[0], w) for w in v) + if p.key == DICTOF: + return dict((encode(p[0], k), encode(p[1], w)) for (k, w) in v.items()) + if p.key == REF: + return v._encode() + if p.key == REC: + return Record(encode(p[0], v), encode(p[1], v)) + if p.key == TUPLE: + return tuple(encode(pp, v) for pp in p[0]) + if p.key == TUPLE_PREFIX: + return tuple(encode(pp, v) for pp in p[0]) + encode(p[1], v) + if p.key == DICT: + return dict((k, encode(pp, v)) for (k, pp) in p[0].items()) + raise ValueError('Bad schema') + def module_path_str(mp): return '.'.join([e.name for e in mp]) @@ -392,6 +430,8 @@ if __name__ == '__main__': with open(__metaschema_filename, 'rb') as f: x = Decoder(f.read()).next() print(meta.Schema.decode(x)) + print(meta.Schema.decode(x)._encode()) + assert meta.Schema.decode(x)._encode() == x @extend(meta.Schema) def f(self, x): @@ -407,5 +447,8 @@ if __name__ == '__main__': x = Decoder(f.read()).next() print(meta.Schema.decode(x)) print(meta.Schema.decode(x) == meta.Schema.decode(x)) + print(meta.Schema.decode(x)._encode()) + assert meta.Schema.decode(x)._encode() == x + print() print(path)