Skip to content

dswistowski/svarog

Repository files navigation

Svarog

image

image

Documentation Status

Svarog allow to create object from non typed data. All it need is annotated __init__ method:

>>> from svarog import forge ... class A: ... def __init__(self, a: int, b: str): ... self._a = a ... self._b = b ... def __repr__(self): ... return f'A(a={self._a}, b="{self._b}")' >>> forge(A, {"a": 1, "b": "3"}) A(a=1, b="3")

More complicated types as Sequence, Mapping, Optional are possible

>>> class A: ... def __init__(self, b: Sequence[int]): ... self._b = b ... def __repr__(self): ... return f'A(b={self._b})' >>> forge(A, {"b": "3213"}) A(b=[3, 2, 1, 3])

You can use forward refs:

>>> class WithRef: ... def __init__(self, child: Optional['WithRef']): ... self._child = child ... def __repr__(self): ... return f"WithRef({self._child!r})" >>> forge(WithRef(WithRef(WithRef()))) WithRef(WithRef(WithRef(None)))

Objects are forged recursively:

>>> @dataclass ... class A: ... b: 'B' ... c: 'C' ... @dataclass ... class B: ... number: int ... @dataclass ... class C: ... string: str >>> forge(A, {'b': {'number': 42}, 'c': {'string': 'the-string'}}) A(b=B(number=42), c=C(string='the-string'))

You can register own forge for your classes:

>>> class FooType(Enum): ... LOREM = "lorem" ... IPSUM = "ipsum" ... ... class FooParams: ... types: ClassVar[Mapping[FooType, "FooParams"]] = {} ... def __init_subclass__(cls, type: FooType): ... cls.types[type] = cls ... ... @classmethod ... def for_type(cls, type): ... return cls.types[type] ... ... @dataclass ... class LoremFooParams(FooParams, type=FooType.LOREM): ... lorem: str ... ... @dataclass ... class IpsumFooParams(FooParams, type=FooType.IPSUM): ... ipsum: int ... ... @dataclass ... class Foo: ... type: FooType ... params: FooParams ... ... @classmethod ... def forge(cls, _, data, forge): ... foo_type = forge(FooType, data["type"]) ... return Foo( ... type=forge(FooType, foo_type), ... params=forge(FooParams.for_type(foo_type), data["params"]) ... ) ... >>> register_forge(Foo, Foo.forge) >>> forge(Foo, {"type": "lorem", "params": {"lorem": "foo-bar"}}) Foo(type=<FooType.LOREM: 'lorem'>, params=LoremFooParams(lorem='foo-bar'))

>>> forge(Foo, {"type": "ipsum", "params": {"ipsum": 42}}) Foo(type=<FooType.IPSUM: 'ipsum'>, params=IpsumFooParams(ipsum=42))

Support for CamelCase to snake_case convertion:

>>> class Snake: ... lorem_ipsum: int >>> forge = Svarog(snake_case=True).forge >>> forge(Snake, {"LoremIpsum": 42}) Snake(lorem_ipsum=42)

Features

  • Converts unstructured data into structured recursively
    • Works with dataclasses
    • Works with Sequence, Mapping, Optional
    • Special conventers for types can be registered with

Credits

Some parts of this code, and concept borrowed from cattrs project

This package was created with Cookiecutter and the audreyr/cookiecutter-pypackage project template.

About

Svarog is a python library allowing to structure types from non-structured data

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 4

  •  
  •  
  •  
  •