77 lines
2.6 KiB
Python
77 lines
2.6 KiB
Python
import dataclasses
|
|
from dataclasses import dataclass, _MISSING_TYPE
|
|
from munch import Munch
|
|
|
|
EXPECTED = "___REQUIRED___"
|
|
EXPECTED_TRAIN = "___REQUIRED_TRAIN___"
|
|
|
|
|
|
# pylint: disable=invalid-field-call
|
|
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 = dataclasses.asdict(self) # needs to pickle stuff, doesn't support some more complex classes
|
|
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
|