1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
from collections.abc import Callable
from dataclasses import dataclass
from types import NoneType
from typing import Any
from copy import deepcopy
@dataclass
class CruAttr:
name: str
value: Any
description: str
@dataclass
class CruAttrDef:
name: str
default_description: str
allow_types: None | set[type]
allow_none: bool
default_value: Any
transformer: Callable[[Any], Any] | None
validator: Callable[[Any], None]
def __init__(self, name: str, default_description: str, *,
allow_types: list[type] | type | None, allow_none: bool, default_value: Any = None,
transformer: Callable[[Any], Any] | None = None,
validator: Callable[[Any], None] | None = None) -> None:
self.name = name
self.default_description = default_description
self.default_value = default_value
#TODO: CONTINUE TOMORROW
if allow_types is None:
allow_types = []
elif isinstance(allow_types, type):
allow_types = [allow_types]
else:
for t in allow_types:
if not isinstance(t, type):
raise TypeError(f"Invalid value of python type : {t}")
self.allow_types = set(filter(lambda tt: tt is not NoneType, allow_types))
self.allow_none = allow_none
self.transformer = transformer
self.validator = validator
self.default_value = self.transform_and_validate(self.default_value)
self.default_value = deepcopy(self.default_value)
def transform(self, value: Any) -> Any:
if self.transformer is not None:
return self.transformer(value)
return value
def validate(self, value: Any, /, override_allow_none: bool | None = None) -> None:
allow_none = override_allow_none if override_allow_none is not None else self.allow_none
if value is None and not allow_none:
raise TypeError(f"None is not allowed!")
if len(self.allow_types) != 0 and type(value) not in self.allow_types:
raise TypeError(f"Type of {value} is not allowed!")
if self.validator is not None:
return self.validator(value)
return None
def transform_and_validate(self, value: Any, /, override_allow_none: bool | None = None) -> Any:
value = self.transform(value)
self.validate(value, override_allow_none)
return value
def make(self, value: Any, description: None | str = None) -> CruAttr:
value = self.transform_and_validate(value)
return CruAttr(self.name, value if value is not None else deepcopy(self.default_value),
description if description is not None else self.default_description)
class CruAttrDefRegistry:
def __init__(self) -> None:
self._def_list = []
@property
def items(self) -> list[CruAttrDef]:
return self._def_list
def register(self, def_: CruAttrDef):
for i in self._def_list:
if i.name == def_.name:
raise ValueError(f"Attribute {def_.name} already exists!")
self._def_list.append(def_)
def register_with(self, name: str, default_description: str, *,
allow_types: list[type] | type | None, allow_none: bool,
default_value: Any = None,
transformer: Callable[[Any], Any] | None = None,
validator: Callable[[Any], None] | None = None
) -> CruAttrDef:
def_ = CruAttrDef(name, default_description, default_value=default_value, allow_types=allow_types,
allow_none=allow_none, transformer=transformer, validator=validator)
self.register(def_)
return def_
def register_required(self, name: str, default_description: str, *,
allow_types: list[type] | type | None,
default_value: Any = None,
transformer: Callable[[Any], Any] | None = None,
validator: Callable[[Any], None] | None = None
) -> CruAttrDef:
return self.register_with(name, default_description, default_value=default_value, allow_types=allow_types,
allow_none=False, transformer=transformer, validator=validator)
def register_optional(self, name: str, default_description: str, *,
allow_types: list[type] | type | None,
default_value: Any = None,
transformer: Callable[[Any], Any] | None = None,
validator: Callable[[Any], None] | None = None
) -> CruAttrDef:
return self.register_with(name, default_description, default_value=default_value, allow_types=allow_types,
allow_none=True, transformer=transformer, validator=validator)
def get_item_optional(self, name: str) -> CruAttrDef | None:
for i in self._def_list:
if i.name == name:
return i
return None
def __getitem__(self, item) -> CruAttrDef | None:
return self.get_item_optional(item)
|