Add helpers module

This commit is contained in:
Maks Snegov 2020-09-10 21:45:06 +03:00
parent a6b8d7f2d3
commit 8f2e0f5db9
3 changed files with 112 additions and 0 deletions

11
setup.py Normal file
View File

@ -0,0 +1,11 @@
from setuptools import setup, find_packages
setup(
name="spqr.kieran",
version="0.0.1",
author="Maks Snegov",
author_email="snegov@spqr.link",
description="Helpers for SPQR projects",
packages=find_packages(),
python_requires=">=3.8",
)

6
spqr/kieran/__init__.py Normal file
View File

@ -0,0 +1,6 @@
from .helpers import (
nested_dataclass,
ExtraDataclass,
singleton,
ConstEnum
)

95
spqr/kieran/helpers.py Normal file
View File

@ -0,0 +1,95 @@
from dataclasses import dataclass, is_dataclass, fields, asdict
from enum import Enum
from typing import Sequence
def nested_dataclass(*args, **kwargs):
def wrapper(cls):
cls = dataclass(cls, **kwargs)
original_init = cls.__init__
def __init__(self, *args, **kwargs):
for name, value in kwargs.items():
field_type = cls.__annotations__.get(name, None)
if is_dataclass(field_type) and isinstance(value, dict):
new_obj = field_type(**value)
kwargs[name] = new_obj
original_init(self, *args, **kwargs)
cls.__init__ = __init__
return cls
return wrapper(args[0]) if args else wrapper
@dataclass
class ExtraDataclass:
@classmethod
def from_dict(cls, data: dict):
""" Create dataclass from dict ignoring extra arguments. """
cl_fields = set([f.name for f in fields(cls)])
filtered_data = dict()
for k, v in data.items():
if k in cl_fields:
filtered_data[k] = v
return cls(**filtered_data)
@classmethod
def from_list(cls, ent_list: Sequence[dict]) -> list:
""" Create list of dataclass instances from list of dicts. """
return [cls.from_dict(ent) for ent in ent_list]
def to_dict(self) -> dict:
""" Returns dict with not None values """
return asdict(
self, dict_factory=lambda d: {k: v for k, v in d if v is not None}
)
def singleton(class_):
instances = {}
def get_instance(*args, **kwargs):
if class_ not in instances:
instances[class_] = class_(*args, **kwargs)
return instances[class_]
return get_instance
class ConstEnum(str, Enum):
"""
Class is used for gathering string constants in one place.
Attribute values are generated from attribute names.
All attributes values will be considered as strings.
Class name is omitted from attribute value.
>>> Booze = ConstEnum("Booze", "Whiskey Beer Vodka")
>>> Booze.Beer
Beer
>>> print(Booze.Beer)
Beer
>>> type(Booze.Vodka)
<enum 'Booze'>
>>> repr(Booze.Whiskey)
'Whiskey'
Also could be used with usual class creation:
>>> from enum import auto
>>> class NotBooze(ConstEnum):
>>> Juice = auto()
>>> Tea = auto()
>>> Coffee = auto()
>>> repr(NotBooze.Tea)
'Tea'
"""
def _generate_next_value_(name, start, count, last_values):
return name
def __repr__(self):
return self.name
def __str__(self):
return self.name