Skip to content

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

License

Notifications You must be signed in to change notification settings

dswistowski/svarog

Repository files navigation

Svarog

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

  •  
  •  
  •  
  •