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

Feature completeness

parent 5ec2e899
This diff is collapsed.
from typing import Optional from typing import Optional, Union
from typeguard import check_type from typeguard import check_type
...@@ -86,7 +86,7 @@ class Deserializable(metaclass=BaseMeta): ...@@ -86,7 +86,7 @@ class Deserializable(metaclass=BaseMeta):
return fields return fields
def deserialize(t, d, try_all=False): def get_deserialization_class(t, d, try_all=False):
for sc in t.__subclasses__(): for sc in t.__subclasses__():
if hasattr(sc, '_discriminators'): if hasattr(sc, '_discriminators'):
for discriminator in sc._discriminators: for discriminator in sc._discriminators:
...@@ -94,17 +94,42 @@ def deserialize(t, d, try_all=False): ...@@ -94,17 +94,42 @@ def deserialize(t, d, try_all=False):
break break
else: else:
try: try:
return deserialize(sc, d) return get_deserialization_class(sc, t, try_all)
except TypeError as e: except TypeError as e:
if not try_all: if not try_all:
raise e raise e
return t
if hasattr(t, '_abstract') and t._abstract:
raise TypeError('Cannot deserialize into {}: is abstract.'.format(t.__name__))
instance = t() def deserialize(rule: Rule, data, try_all=False, key=None):
for k, rule in t.get_attrs().items(): # In case of primitive types, attempt to assign.
v = rule.validate(k, d[k] if k in d else None) try:
setattr(instance, k, v) 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 time import sleep
from typing import Optional from typing import Optional
from serializer_utils.deserializer import Deserializable from serializer_utils.deserializer import Deserializable, Rule
from serializer_utils.annotations import abstract, discriminate from serializer_utils.annotations import abstract, discriminate
...@@ -32,16 +32,34 @@ class RefundLine(ReceiptLine): ...@@ -32,16 +32,34 @@ class RefundLine(ReceiptLine):
return 'RefundLine(super={})'.format(super(RefundLine, self).__repr__()) return 'RefundLine(super={})'.format(super(RefundLine, self).__repr__())
class Test(Deserializable):
tf: Optional[ReceiptLine]
def __repr__(self):
return 'Test(tf={})'.format(
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
import traceback import traceback
from serializer_utils.deserializer import deserialize from serializer_utils.deserializer import deserialize
try: def print_result(function, *args, **kwargs):
print(deserialize(ReceiptLine, {'type': 'transaction', 'name': 'asdf', 'article_id': 5, 'amount': 5})) try:
print(deserialize(ReceiptLine, {'type': 'refund', 'name': 'asdf', 'pk': 5})) print(function(*args, **kwargs))
print(deserialize(ReceiptLine, {'type': 'other', 'name': 'asdf'})) except:
except TypeError as err: sleep(0.05)
sleep(0.05) print(traceback.format_exc(), file=sys.stderr)
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]
Markdown is supported
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