Commit 6e7391cb authored by Rolf van Kleef's avatar Rolf van Kleef
Browse files

Feature completeness

parent 5ec2e899
This diff is collapsed.
from typing import Optional
from typing import Optional, Union
from typeguard import check_type
......@@ -86,7 +86,7 @@ class Deserializable(metaclass=BaseMeta):
return fields
def deserialize(t, d, try_all=False):
def get_deserialization_class(t, d, try_all=False):
for sc in t.__subclasses__():
if hasattr(sc, '_discriminators'):
for discriminator in sc._discriminators:
......@@ -94,17 +94,42 @@ def deserialize(t, d, try_all=False):
return deserialize(sc, d)
return get_deserialization_class(sc, t, try_all)
except TypeError as e:
if not try_all:
raise e
return t
if hasattr(t, '_abstract') and t._abstract:
raise TypeError('Cannot deserialize into {}: is abstract.'.format(t.__name__))
instance = t()
for k, rule in t.get_attrs().items():
v = rule.validate(k, d[k] if k in d else None)
setattr(instance, k, v)
def deserialize(rule: Rule, data, try_all=False, key=None):
# In case of primitive types, attempt to assign.
return rule.validate(key, data)
except TypeError:
return instance
if type(rule.type) is type(Union):
for arg in rule.type.__args__:
return deserialize(Rule(arg), data, try_all, key)
except TypeError:
raise TypeError('{} did not match any of {}.'.format(type(data), rule.type.__args__))
if issubclass(rule.type, Deserializable):
if not isinstance(data, dict):
raise TypeError('Cannot deserialize non-dict into class.')
cls = get_deserialization_class(rule.type, data, try_all)
if hasattr(cls, '_abstract') and cls._abstract:
raise TypeError('Cannot deserialize into {}: is abstract.'.format(cls.__name__))
instance = cls()
for k, r in cls.get_attrs().items():
v = deserialize(r, data[k] if k in data else r.default, try_all, key=k)
setattr(instance, k, v)
return instance
raise TypeError('Unable to find a deserialization candidate for {} in {}.'.format(data, rule))
\ No newline at end of file
from time import sleep
from typing import Optional
from serializer_utils.deserializer import Deserializable
from serializer_utils.deserializer import Deserializable, Rule
from serializer_utils.annotations import abstract, discriminate
......@@ -32,16 +32,34 @@ class RefundLine(ReceiptLine):
return 'RefundLine(super={})'.format(super(RefundLine, self).__repr__())
class Test(Deserializable):
tf: Optional[ReceiptLine]
def __repr__(self):
return 'Test(tf={})'.format(
if __name__ == '__main__':
import sys
import traceback
from serializer_utils.deserializer import deserialize
print(deserialize(ReceiptLine, {'type': 'transaction', 'name': 'asdf', 'article_id': 5, 'amount': 5}))
print(deserialize(ReceiptLine, {'type': 'refund', 'name': 'asdf', 'pk': 5}))
print(deserialize(ReceiptLine, {'type': 'other', 'name': 'asdf'}))
except TypeError as err:
print(traceback.format_exc(), file=sys.stderr)
def print_result(function, *args, **kwargs):
print(function(*args, **kwargs))
print(traceback.format_exc(), file=sys.stderr)
fns = [
[Rule(ReceiptLine), {'type': 'transaction', 'name': 'asdf', 'article_id': 5, 'amount': 5}],
[Rule(ReceiptLine), {'type': 'refund', 'name': 'asdf', 'pk': 5}],
[Rule(ReceiptLine), {'type': 'other', 'name': 'asdf'}],
[Rule(ReceiptLine), {'type': 'transaction'}],
[Rule(ReceiptLine), {'type': 'transaction', 'name': 'asdf', 'pk': 'no'}],
[Rule(Test), {'tf': {'type': 'refund', 'name': 'asdf', 'pk': 5}}]
[print_result(deserialize, *entry) for entry in fns]
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment