|
import dataclasses |
|
from dataclasses import dataclass, _MISSING_TYPE |
|
from munch import Munch |
|
|
|
EXPECTED = "___REQUIRED___" |
|
EXPECTED_TRAIN = "___REQUIRED_TRAIN___" |
|
|
|
|
|
def nested_dto(x, raw=False): |
|
return dataclasses.field(default_factory=lambda: x if raw else Munch.fromDict(x)) |
|
|
|
@dataclass(frozen=True) |
|
class Base: |
|
training: bool = None |
|
def __new__(cls, **kwargs): |
|
training = kwargs.get('training', True) |
|
setteable_fields = cls.setteable_fields(**kwargs) |
|
mandatory_fields = cls.mandatory_fields(**kwargs) |
|
invalid_kwargs = [ |
|
{k: v} for k, v in kwargs.items() if k not in setteable_fields or v == EXPECTED or (v == EXPECTED_TRAIN and training is not False) |
|
] |
|
print(mandatory_fields) |
|
assert ( |
|
len(invalid_kwargs) == 0 |
|
), f"Invalid fields detected when initializing this DTO: {invalid_kwargs}.\nDeclare this field and set it to None or EXPECTED in order to make it setteable." |
|
missing_kwargs = [f for f in mandatory_fields if f not in kwargs] |
|
assert ( |
|
len(missing_kwargs) == 0 |
|
), f"Required fields missing initializing this DTO: {missing_kwargs}." |
|
return object.__new__(cls) |
|
|
|
|
|
@classmethod |
|
def setteable_fields(cls, **kwargs): |
|
return [f.name for f in dataclasses.fields(cls) if f.default is None or isinstance(f.default, _MISSING_TYPE) or f.default == EXPECTED or f.default == EXPECTED_TRAIN] |
|
|
|
@classmethod |
|
def mandatory_fields(cls, **kwargs): |
|
training = kwargs.get('training', True) |
|
return [f.name for f in dataclasses.fields(cls) if isinstance(f.default, _MISSING_TYPE) and isinstance(f.default_factory, _MISSING_TYPE) or f.default == EXPECTED or (f.default == EXPECTED_TRAIN and training is not False)] |
|
|
|
@classmethod |
|
def from_dict(cls, kwargs): |
|
for k in kwargs: |
|
if isinstance(kwargs[k], (dict, list, tuple)): |
|
kwargs[k] = Munch.fromDict(kwargs[k]) |
|
return cls(**kwargs) |
|
|
|
def to_dict(self): |
|
|
|
selfdict = {} |
|
for k in dataclasses.fields(self): |
|
selfdict[k.name] = getattr(self, k.name) |
|
if isinstance(selfdict[k.name], Munch): |
|
selfdict[k.name] = selfdict[k.name].toDict() |
|
return selfdict |
|
|