GeneralManager 0.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- general_manager/__init__.py +0 -0
- general_manager/api/graphql.py +732 -0
- general_manager/api/mutation.py +143 -0
- general_manager/api/property.py +20 -0
- general_manager/apps.py +83 -0
- general_manager/auxiliary/__init__.py +2 -0
- general_manager/auxiliary/argsToKwargs.py +25 -0
- general_manager/auxiliary/filterParser.py +97 -0
- general_manager/auxiliary/noneToZero.py +12 -0
- general_manager/cache/cacheDecorator.py +72 -0
- general_manager/cache/cacheTracker.py +33 -0
- general_manager/cache/dependencyIndex.py +300 -0
- general_manager/cache/pathMapping.py +151 -0
- general_manager/cache/signals.py +48 -0
- general_manager/factory/__init__.py +5 -0
- general_manager/factory/factories.py +287 -0
- general_manager/factory/lazy_methods.py +38 -0
- general_manager/interface/__init__.py +3 -0
- general_manager/interface/baseInterface.py +308 -0
- general_manager/interface/calculationInterface.py +406 -0
- general_manager/interface/databaseInterface.py +726 -0
- general_manager/manager/__init__.py +3 -0
- general_manager/manager/generalManager.py +136 -0
- general_manager/manager/groupManager.py +288 -0
- general_manager/manager/input.py +48 -0
- general_manager/manager/meta.py +75 -0
- general_manager/measurement/__init__.py +2 -0
- general_manager/measurement/measurement.py +233 -0
- general_manager/measurement/measurementField.py +152 -0
- general_manager/permission/__init__.py +1 -0
- general_manager/permission/basePermission.py +178 -0
- general_manager/permission/fileBasedPermission.py +0 -0
- general_manager/permission/managerBasedPermission.py +171 -0
- general_manager/permission/permissionChecks.py +53 -0
- general_manager/permission/permissionDataManager.py +55 -0
- general_manager/rule/__init__.py +1 -0
- general_manager/rule/handler.py +122 -0
- general_manager/rule/rule.py +313 -0
- generalmanager-0.0.0.dist-info/METADATA +207 -0
- generalmanager-0.0.0.dist-info/RECORD +43 -0
- generalmanager-0.0.0.dist-info/WHEEL +5 -0
- generalmanager-0.0.0.dist-info/licenses/LICENSE +29 -0
- generalmanager-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Generic, Type, Any, TYPE_CHECKING
|
3
|
+
from general_manager.manager.meta import GeneralManagerMeta
|
4
|
+
from general_manager.interface.baseInterface import (
|
5
|
+
InterfaceBase,
|
6
|
+
Bucket,
|
7
|
+
GeneralManagerType,
|
8
|
+
)
|
9
|
+
from general_manager.api.property import GraphQLProperty
|
10
|
+
from general_manager.cache.cacheTracker import addDependency
|
11
|
+
from general_manager.cache.signals import dataChange
|
12
|
+
|
13
|
+
if TYPE_CHECKING:
|
14
|
+
from general_manager.permission.basePermission import BasePermission
|
15
|
+
|
16
|
+
|
17
|
+
class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
|
18
|
+
Interface: Type[InterfaceBase]
|
19
|
+
_attributes: dict[str, Any]
|
20
|
+
|
21
|
+
def __init__(self, *args: Any, **kwargs: Any):
|
22
|
+
self._interface = self.Interface(*args, **kwargs)
|
23
|
+
self.__id: dict[str, Any] = self._interface.identification
|
24
|
+
addDependency(self.__class__.__name__, "identification", f"{self.__id}")
|
25
|
+
|
26
|
+
def __str__(self):
|
27
|
+
return f"{self.__class__.__name__}(**{self.__id})"
|
28
|
+
|
29
|
+
def __repr__(self):
|
30
|
+
return f"{self.__class__.__name__}(**{self.__id})"
|
31
|
+
|
32
|
+
def __reduce__(self) -> str | tuple[Any, ...]:
|
33
|
+
return (self.__class__, tuple(self.__id.values()))
|
34
|
+
|
35
|
+
def __or__(
|
36
|
+
self, other: GeneralManager[GeneralManagerType] | Bucket[GeneralManagerType]
|
37
|
+
) -> Bucket[GeneralManagerType]:
|
38
|
+
if isinstance(other, Bucket):
|
39
|
+
return other | self
|
40
|
+
elif isinstance(other, GeneralManager) and other.__class__ == self.__class__:
|
41
|
+
return self.filter(id__in=[self.__id, other.__id])
|
42
|
+
else:
|
43
|
+
raise TypeError(f"Unsupported type for union: {type(other)}")
|
44
|
+
|
45
|
+
@property
|
46
|
+
def identification(self):
|
47
|
+
return self.__id
|
48
|
+
|
49
|
+
def __iter__(self):
|
50
|
+
for key, value in self._attributes.items():
|
51
|
+
if callable(value):
|
52
|
+
yield key, value(self._interface)
|
53
|
+
continue
|
54
|
+
yield key, value
|
55
|
+
for name, value in self.__class__.__dict__.items():
|
56
|
+
if isinstance(value, (GraphQLProperty, property)):
|
57
|
+
yield name, getattr(self, name)
|
58
|
+
|
59
|
+
@classmethod
|
60
|
+
@dataChange
|
61
|
+
def create(
|
62
|
+
cls,
|
63
|
+
creator_id: int,
|
64
|
+
history_comment: str | None = None,
|
65
|
+
ignore_permission: bool = False,
|
66
|
+
**kwargs: dict[str, Any],
|
67
|
+
) -> GeneralManager[GeneralManagerType]:
|
68
|
+
Permission: Type[BasePermission] | None = getattr(cls, "Permission", None)
|
69
|
+
if Permission is not None and not ignore_permission:
|
70
|
+
Permission.checkCreatePermission(kwargs, cls, creator_id)
|
71
|
+
identification = cls.Interface.create(
|
72
|
+
creator_id=creator_id, history_comment=history_comment, **kwargs
|
73
|
+
)
|
74
|
+
return cls(identification)
|
75
|
+
|
76
|
+
@dataChange
|
77
|
+
def update(
|
78
|
+
self,
|
79
|
+
creator_id: int,
|
80
|
+
history_comment: str | None = None,
|
81
|
+
ignore_permission: bool = False,
|
82
|
+
**kwargs: dict[str, Any],
|
83
|
+
) -> GeneralManager[GeneralManagerType]:
|
84
|
+
Permission: Type[BasePermission] | None = getattr(self, "Permission", None)
|
85
|
+
if Permission is not None and not ignore_permission:
|
86
|
+
Permission.checkUpdatePermission(kwargs, self, creator_id)
|
87
|
+
self._interface.update(
|
88
|
+
creator_id=creator_id,
|
89
|
+
history_comment=history_comment,
|
90
|
+
**kwargs,
|
91
|
+
)
|
92
|
+
return self.__class__(**self.identification)
|
93
|
+
|
94
|
+
@dataChange
|
95
|
+
def deactivate(
|
96
|
+
self,
|
97
|
+
creator_id: int,
|
98
|
+
history_comment: str | None = None,
|
99
|
+
ignore_permission: bool = False,
|
100
|
+
) -> GeneralManager[GeneralManagerType]:
|
101
|
+
Permission: Type[BasePermission] | None = getattr(self, "Permission", None)
|
102
|
+
if Permission is not None and not ignore_permission:
|
103
|
+
Permission.checkDeletePermission(self, creator_id)
|
104
|
+
self._interface.deactivate(
|
105
|
+
creator_id=creator_id, history_comment=history_comment
|
106
|
+
)
|
107
|
+
return self.__class__(**self.identification)
|
108
|
+
|
109
|
+
@classmethod
|
110
|
+
def filter(cls, **kwargs: Any) -> Bucket[GeneralManagerType]:
|
111
|
+
addDependency(cls.__name__, "filter", f"{cls.__parse_identification(kwargs)}")
|
112
|
+
return cls.Interface.filter(**kwargs)
|
113
|
+
|
114
|
+
@classmethod
|
115
|
+
def exclude(cls, **kwargs: Any) -> Bucket[GeneralManagerType]:
|
116
|
+
addDependency(cls.__name__, "exclude", f"{cls.__parse_identification(kwargs)}")
|
117
|
+
return cls.Interface.exclude(**kwargs)
|
118
|
+
|
119
|
+
@classmethod
|
120
|
+
def all(cls) -> Bucket[GeneralManagerType]:
|
121
|
+
return cls.Interface.filter()
|
122
|
+
|
123
|
+
@staticmethod
|
124
|
+
def __parse_identification(kwargs: dict[str, Any]) -> dict[str, Any] | None:
|
125
|
+
for key, value in kwargs.items():
|
126
|
+
if isinstance(value, GeneralManager):
|
127
|
+
kwargs[key] = value.identification
|
128
|
+
elif isinstance(value, list):
|
129
|
+
kwargs[key] = [
|
130
|
+
v.identification for v in value if isinstance(v, GeneralManager)
|
131
|
+
]
|
132
|
+
elif isinstance(value, tuple):
|
133
|
+
kwargs[key] = tuple(
|
134
|
+
v.identification for v in value if isinstance(v, GeneralManager)
|
135
|
+
)
|
136
|
+
return kwargs if kwargs else None
|
@@ -0,0 +1,288 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import (
|
3
|
+
Type,
|
4
|
+
Generator,
|
5
|
+
Any,
|
6
|
+
Generic,
|
7
|
+
get_args,
|
8
|
+
cast,
|
9
|
+
)
|
10
|
+
import json
|
11
|
+
from datetime import datetime, date, time
|
12
|
+
from general_manager.api.graphql import GraphQLProperty
|
13
|
+
from general_manager.measurement import Measurement
|
14
|
+
from general_manager.manager.generalManager import GeneralManager
|
15
|
+
from general_manager.interface.baseInterface import (
|
16
|
+
Bucket,
|
17
|
+
GeneralManagerType,
|
18
|
+
)
|
19
|
+
|
20
|
+
|
21
|
+
class GroupBucket(Bucket[GeneralManagerType]):
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
manager_class: Type[GeneralManagerType],
|
26
|
+
group_by_keys: tuple[str, ...],
|
27
|
+
data: Bucket[GeneralManagerType],
|
28
|
+
):
|
29
|
+
super().__init__(manager_class)
|
30
|
+
self.__checkGroupByArguments(group_by_keys)
|
31
|
+
self._group_by_keys = group_by_keys
|
32
|
+
self._data = self.__buildGroupedManager(data)
|
33
|
+
self._basis_data = data
|
34
|
+
|
35
|
+
def __checkGroupByArguments(self, group_by_keys: tuple[str, ...]) -> None:
|
36
|
+
"""
|
37
|
+
This method checks if the given arguments are valid for the groupBy method.
|
38
|
+
It raises a TypeError if the arguments are not valid.
|
39
|
+
"""
|
40
|
+
if not all(isinstance(arg, str) for arg in group_by_keys):
|
41
|
+
raise TypeError("groupBy() argument must be a string")
|
42
|
+
if not all(
|
43
|
+
arg in self._manager_class.Interface.getAttributes().keys()
|
44
|
+
for arg in group_by_keys
|
45
|
+
):
|
46
|
+
raise TypeError(
|
47
|
+
f"groupBy() argument must be a valid attribute of {self._manager_class.__name__}"
|
48
|
+
)
|
49
|
+
|
50
|
+
def __buildGroupedManager(
|
51
|
+
self,
|
52
|
+
data: Bucket[GeneralManagerType],
|
53
|
+
) -> list[GroupedManager[GeneralManagerType]]:
|
54
|
+
"""
|
55
|
+
This method builds the grouped manager.
|
56
|
+
It returns a GroupBucket with the grouped data.
|
57
|
+
"""
|
58
|
+
group_by_values = set()
|
59
|
+
for entry in data:
|
60
|
+
group_by_value = {}
|
61
|
+
for arg in self._group_by_keys:
|
62
|
+
group_by_value[arg] = getattr(entry, arg)
|
63
|
+
group_by_values.add(json.dumps(group_by_value))
|
64
|
+
|
65
|
+
groups = []
|
66
|
+
for group_by_value in group_by_values:
|
67
|
+
group_by_value = json.loads(group_by_value)
|
68
|
+
grouped_manager_objects = data.filter(**group_by_value)
|
69
|
+
groups.append(
|
70
|
+
GroupedManager(
|
71
|
+
self._manager_class, group_by_value, grouped_manager_objects
|
72
|
+
)
|
73
|
+
)
|
74
|
+
return groups
|
75
|
+
|
76
|
+
def __or__(self, other: object) -> GroupBucket[GeneralManagerType]:
|
77
|
+
if not isinstance(other, self.__class__):
|
78
|
+
raise ValueError("Cannot combine different bucket types")
|
79
|
+
if self._manager_class != other._manager_class:
|
80
|
+
raise ValueError("Cannot combine different manager classes")
|
81
|
+
return GroupBucket(
|
82
|
+
self._manager_class,
|
83
|
+
self._group_by_keys,
|
84
|
+
self._basis_data | other._basis_data,
|
85
|
+
)
|
86
|
+
|
87
|
+
def __iter__(self) -> Generator[GroupedManager[GeneralManagerType]]:
|
88
|
+
for grouped_manager in self._data:
|
89
|
+
yield grouped_manager
|
90
|
+
|
91
|
+
def filter(self, **kwargs: Any) -> GroupBucket[GeneralManagerType]:
|
92
|
+
new_basis_data = self._basis_data.filter(**kwargs)
|
93
|
+
return GroupBucket(
|
94
|
+
self._manager_class,
|
95
|
+
self._group_by_keys,
|
96
|
+
new_basis_data,
|
97
|
+
)
|
98
|
+
|
99
|
+
def exclude(self, **kwargs: Any) -> GroupBucket[GeneralManagerType]:
|
100
|
+
new_basis_data = self._basis_data.exclude(**kwargs)
|
101
|
+
return GroupBucket(
|
102
|
+
self._manager_class,
|
103
|
+
self._group_by_keys,
|
104
|
+
new_basis_data,
|
105
|
+
)
|
106
|
+
|
107
|
+
def first(self) -> GroupedManager[GeneralManagerType] | None:
|
108
|
+
try:
|
109
|
+
return next(iter(self))
|
110
|
+
except StopIteration:
|
111
|
+
return None
|
112
|
+
|
113
|
+
def last(self) -> GroupedManager[GeneralManagerType] | None:
|
114
|
+
items = list(self)
|
115
|
+
if items:
|
116
|
+
return items[-1]
|
117
|
+
return None
|
118
|
+
|
119
|
+
def count(self) -> int:
|
120
|
+
return sum(1 for _ in self)
|
121
|
+
|
122
|
+
def all(self) -> Bucket[GeneralManagerType]:
|
123
|
+
return self
|
124
|
+
|
125
|
+
def get(self, **kwargs: Any) -> GroupedManager[GeneralManagerType]:
|
126
|
+
first_value = self.filter(**kwargs).first()
|
127
|
+
if first_value is None:
|
128
|
+
raise ValueError(
|
129
|
+
f"Cannot find {self._manager_class.__name__} with {kwargs}"
|
130
|
+
)
|
131
|
+
return first_value
|
132
|
+
|
133
|
+
def __getitem__(
|
134
|
+
self, item: int | slice
|
135
|
+
) -> GroupedManager[GeneralManagerType] | GroupBucket[GeneralManagerType]:
|
136
|
+
if isinstance(item, int):
|
137
|
+
return self._data[item]
|
138
|
+
elif isinstance(item, slice):
|
139
|
+
new_data = self._data[item]
|
140
|
+
new_base_data = None
|
141
|
+
for manager in new_data:
|
142
|
+
if new_base_data is None:
|
143
|
+
new_base_data = manager._data
|
144
|
+
else:
|
145
|
+
new_base_data = new_base_data | manager._data
|
146
|
+
if new_base_data is None:
|
147
|
+
raise ValueError("Cannot slice an empty GroupBucket")
|
148
|
+
return GroupBucket(self._manager_class, self._group_by_keys, new_base_data)
|
149
|
+
raise TypeError(f"Invalid argument type: {type(item)}. Expected int or slice.")
|
150
|
+
|
151
|
+
def __len__(self) -> int:
|
152
|
+
return self.count()
|
153
|
+
|
154
|
+
def __contains__(self, item: GeneralManagerType) -> bool:
|
155
|
+
return item in self._basis_data
|
156
|
+
|
157
|
+
def sort(
|
158
|
+
self,
|
159
|
+
key: tuple[str] | str,
|
160
|
+
reverse: bool = False,
|
161
|
+
) -> Bucket[GeneralManagerType]:
|
162
|
+
if isinstance(key, str):
|
163
|
+
key = (key,)
|
164
|
+
if reverse:
|
165
|
+
sorted_data = self._data.sort(
|
166
|
+
key=lambda x: tuple([-getattr(x, k) for k in key])
|
167
|
+
)
|
168
|
+
else:
|
169
|
+
sorted_data = self._data.sort(
|
170
|
+
key=lambda x: tuple([getattr(x, k) for k in key])
|
171
|
+
)
|
172
|
+
|
173
|
+
new_bucket = GroupBucket(
|
174
|
+
self._manager_class, self._group_by_keys, self._basis_data
|
175
|
+
)
|
176
|
+
new_bucket._data = sorted_data
|
177
|
+
return new_bucket
|
178
|
+
|
179
|
+
def group_by(self, *group_by_keys: str) -> GroupBucket[GeneralManagerType]:
|
180
|
+
"""
|
181
|
+
This method groups the data by the given arguments.
|
182
|
+
It returns a GroupBucket with the grouped data.
|
183
|
+
"""
|
184
|
+
return GroupBucket(
|
185
|
+
self._manager_class, tuple([*self._group_by_keys, *group_by_keys]), self
|
186
|
+
)
|
187
|
+
|
188
|
+
|
189
|
+
class GroupedManager(Generic[GeneralManagerType]):
|
190
|
+
"""
|
191
|
+
This class is used to group the data of a GeneralManager.
|
192
|
+
It is used to create a new GeneralManager with the grouped data.
|
193
|
+
"""
|
194
|
+
|
195
|
+
def __init__(
|
196
|
+
self,
|
197
|
+
manager_class: Type[GeneralManagerType],
|
198
|
+
group_by_value: dict[str, Any],
|
199
|
+
data: Bucket[GeneralManagerType],
|
200
|
+
):
|
201
|
+
self._manager_class = manager_class
|
202
|
+
self._group_by_value = group_by_value
|
203
|
+
self._data = data
|
204
|
+
self._grouped_data: dict[str, Any] = {}
|
205
|
+
|
206
|
+
def __eq__(self, other: object) -> bool:
|
207
|
+
if not isinstance(other, self.__class__):
|
208
|
+
return False
|
209
|
+
return (
|
210
|
+
self._data == other._data
|
211
|
+
and self._manager_class == other._manager_class
|
212
|
+
and self._group_by_value == other._group_by_value
|
213
|
+
)
|
214
|
+
|
215
|
+
def __hash__(self) -> int:
|
216
|
+
return hash(
|
217
|
+
(self._manager_class, frozenset(self._group_by_value.items()), self._data)
|
218
|
+
)
|
219
|
+
|
220
|
+
def __repr__(self) -> str:
|
221
|
+
return f"{self.__class__.__name__}({self._manager_class}, {self._group_by_value}, {self._data})"
|
222
|
+
|
223
|
+
def __iter__(self):
|
224
|
+
for attribute in self._manager_class.Interface.getAttributes().keys():
|
225
|
+
yield attribute, getattr(self, attribute)
|
226
|
+
for attribute, attr_value in self._manager_class.__dict__.items():
|
227
|
+
if isinstance(attr_value, GraphQLProperty):
|
228
|
+
yield attribute, getattr(self, attribute)
|
229
|
+
|
230
|
+
def __getattr__(self, item: str) -> Any:
|
231
|
+
if item in self._group_by_value:
|
232
|
+
return self._group_by_value[item]
|
233
|
+
if item not in self._grouped_data.keys():
|
234
|
+
self._grouped_data[item] = self.combineValue(item)
|
235
|
+
return self._grouped_data[item]
|
236
|
+
|
237
|
+
def combineValue(self, item: str) -> Any:
|
238
|
+
if item == "id":
|
239
|
+
return None
|
240
|
+
|
241
|
+
data_type = (
|
242
|
+
self._manager_class.Interface.getAttributeTypes().get(item, {}).get("type")
|
243
|
+
)
|
244
|
+
if data_type is None and item in self._manager_class.__dict__:
|
245
|
+
attr_value = self._manager_class.__dict__[item]
|
246
|
+
if isinstance(attr_value, GraphQLProperty):
|
247
|
+
type_hints = get_args(attr_value.graphql_type_hint)
|
248
|
+
data_type = (
|
249
|
+
type_hints[0]
|
250
|
+
if type_hints
|
251
|
+
else cast(type, attr_value.graphql_type_hint)
|
252
|
+
)
|
253
|
+
if data_type is None:
|
254
|
+
raise AttributeError(f"{self.__class__.__name__} has no attribute {item}")
|
255
|
+
|
256
|
+
total_data = []
|
257
|
+
for entry in self._data:
|
258
|
+
total_data.append(getattr(entry, item))
|
259
|
+
|
260
|
+
new_data = None
|
261
|
+
if all([i is None for i in total_data]):
|
262
|
+
return new_data
|
263
|
+
total_data = [i for i in total_data if i is not None]
|
264
|
+
|
265
|
+
if issubclass(data_type, (Bucket, GeneralManager)):
|
266
|
+
for entry in total_data:
|
267
|
+
if new_data is None:
|
268
|
+
new_data = entry
|
269
|
+
else:
|
270
|
+
new_data = entry | new_data
|
271
|
+
elif issubclass(data_type, list):
|
272
|
+
new_data = []
|
273
|
+
for entry in total_data:
|
274
|
+
new_data.extend(entry)
|
275
|
+
elif issubclass(data_type, dict):
|
276
|
+
new_data = {}
|
277
|
+
for entry in total_data:
|
278
|
+
new_data.update(entry)
|
279
|
+
elif issubclass(data_type, str):
|
280
|
+
new_data = " ".join(total_data)
|
281
|
+
elif issubclass(data_type, (int, float, Measurement)):
|
282
|
+
new_data = sum(total_data)
|
283
|
+
elif issubclass(data_type, (datetime, date, time)):
|
284
|
+
new_data = max(total_data)
|
285
|
+
elif issubclass(data_type, bool):
|
286
|
+
new_data = any(total_data)
|
287
|
+
|
288
|
+
return new_data
|
@@ -0,0 +1,48 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from typing import Iterable, Optional, Callable, List, TypeVar, Generic, Any
|
3
|
+
import inspect
|
4
|
+
|
5
|
+
from general_manager.manager.generalManager import GeneralManager
|
6
|
+
from datetime import date, datetime
|
7
|
+
from general_manager.measurement import Measurement
|
8
|
+
|
9
|
+
|
10
|
+
INPUT_TYPE = TypeVar("INPUT_TYPE", bound=type)
|
11
|
+
|
12
|
+
|
13
|
+
class Input(Generic[INPUT_TYPE]):
|
14
|
+
def __init__(
|
15
|
+
self,
|
16
|
+
type: INPUT_TYPE,
|
17
|
+
possible_values: Optional[Callable | Iterable] = None,
|
18
|
+
depends_on: Optional[List[str]] = None,
|
19
|
+
):
|
20
|
+
self.type = type
|
21
|
+
self.possible_values = possible_values
|
22
|
+
self.is_manager = issubclass(type, GeneralManager)
|
23
|
+
|
24
|
+
if depends_on is not None:
|
25
|
+
# Verwende die angegebenen Abhängigkeiten
|
26
|
+
self.depends_on = depends_on
|
27
|
+
elif callable(possible_values):
|
28
|
+
# Ermittele Abhängigkeiten automatisch aus den Parametern der Funktion
|
29
|
+
sig = inspect.signature(possible_values)
|
30
|
+
self.depends_on = list(sig.parameters.keys())
|
31
|
+
else:
|
32
|
+
# Keine Abhängigkeiten
|
33
|
+
self.depends_on = []
|
34
|
+
|
35
|
+
def cast(self, value: Any) -> Any:
|
36
|
+
if isinstance(value, self.type):
|
37
|
+
return value
|
38
|
+
if issubclass(self.type, GeneralManager):
|
39
|
+
if isinstance(value, dict):
|
40
|
+
return self.type(**value) # type: ignore
|
41
|
+
return self.type(id=value) # type: ignore
|
42
|
+
if self.type == date:
|
43
|
+
return date.fromisoformat(value)
|
44
|
+
if self.type == datetime:
|
45
|
+
return datetime.fromisoformat(value)
|
46
|
+
if self.type == Measurement and isinstance(value, str):
|
47
|
+
return Measurement.from_string(value)
|
48
|
+
return self.type(value)
|
@@ -0,0 +1,75 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
from general_manager.interface.baseInterface import (
|
3
|
+
InterfaceBase,
|
4
|
+
)
|
5
|
+
from django.conf import settings
|
6
|
+
from typing import Any, Type, TYPE_CHECKING, Generic, TypeVar
|
7
|
+
|
8
|
+
if TYPE_CHECKING:
|
9
|
+
from general_manager.interface.databaseInterface import ReadOnlyInterface
|
10
|
+
from general_manager.manager.generalManager import GeneralManager
|
11
|
+
|
12
|
+
GeneralManagerType = TypeVar("GeneralManagerType", bound="GeneralManager")
|
13
|
+
|
14
|
+
|
15
|
+
class GeneralManagerMeta(type):
|
16
|
+
all_classes: list[Type[GeneralManager]] = []
|
17
|
+
read_only_classes: list[Type[ReadOnlyInterface]] = []
|
18
|
+
pending_graphql_interfaces: list[Type[GeneralManager]] = []
|
19
|
+
pending_attribute_initialization: list[Type[GeneralManager]] = []
|
20
|
+
Interface: type[InterfaceBase]
|
21
|
+
|
22
|
+
def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> type:
|
23
|
+
def createNewGeneralManagerClass(
|
24
|
+
mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]
|
25
|
+
) -> Type[GeneralManager]:
|
26
|
+
return super().__new__(mcs, name, bases, attrs)
|
27
|
+
|
28
|
+
if "Interface" in attrs:
|
29
|
+
interface = attrs.pop("Interface")
|
30
|
+
if not issubclass(interface, InterfaceBase):
|
31
|
+
raise TypeError(
|
32
|
+
f"Interface must be a subclass of {InterfaceBase.__name__}"
|
33
|
+
)
|
34
|
+
preCreation, postCreation = interface.handleInterface()
|
35
|
+
attrs, interface_cls, model = preCreation(name, attrs, interface)
|
36
|
+
new_class = createNewGeneralManagerClass(mcs, name, bases, attrs)
|
37
|
+
postCreation(new_class, interface_cls, model)
|
38
|
+
mcs.pending_attribute_initialization.append(new_class)
|
39
|
+
mcs.all_classes.append(new_class)
|
40
|
+
|
41
|
+
else:
|
42
|
+
new_class = createNewGeneralManagerClass(mcs, name, bases, attrs)
|
43
|
+
|
44
|
+
if getattr(settings, "AUTOCREATE_GRAPHQL", False):
|
45
|
+
mcs.pending_graphql_interfaces.append(new_class)
|
46
|
+
|
47
|
+
return new_class
|
48
|
+
|
49
|
+
@staticmethod
|
50
|
+
def createAtPropertiesForAttributes(
|
51
|
+
attributes: dict[str, Any], new_class: Type[GeneralManager]
|
52
|
+
):
|
53
|
+
|
54
|
+
def desciptorMethod(attr_name: str, new_class: type):
|
55
|
+
class Descriptor(Generic[GeneralManagerType]):
|
56
|
+
def __init__(self, attr_name: str, new_class: Type[GeneralManager]):
|
57
|
+
self.attr_name = attr_name
|
58
|
+
self.new_class = new_class
|
59
|
+
|
60
|
+
def __get__(
|
61
|
+
self,
|
62
|
+
instance: GeneralManager[GeneralManagerType] | None,
|
63
|
+
owner: type | None = None,
|
64
|
+
):
|
65
|
+
if instance is None:
|
66
|
+
return self.new_class.Interface.getFieldType(self.attr_name)
|
67
|
+
attribute = instance._attributes[attr_name]
|
68
|
+
if callable(attribute):
|
69
|
+
return attribute(instance._interface)
|
70
|
+
return attribute
|
71
|
+
|
72
|
+
return Descriptor(attr_name, new_class)
|
73
|
+
|
74
|
+
for attr_name in attributes.keys():
|
75
|
+
setattr(new_class, attr_name, desciptorMethod(attr_name, new_class))
|