GeneralManager 0.6.2__py3-none-any.whl → 0.8.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.
@@ -13,13 +13,21 @@ if TYPE_CHECKING:
13
13
  InterfaceBase,
14
14
  )
15
15
  GeneralManagerType = TypeVar("GeneralManagerType", bound="GeneralManager")
16
+ InterfaceType = TypeVar("InterfaceType", bound="InterfaceBase", covariant=True)
16
17
 
17
18
 
18
- class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
19
- Interface: Type[InterfaceBase]
19
+ class GeneralManager(
20
+ Generic[GeneralManagerType, InterfaceType], metaclass=GeneralManagerMeta
21
+ ):
22
+ Interface: Type[InterfaceType]
20
23
  _attributes: dict[str, Any]
21
24
 
22
25
  def __init__(self, *args: Any, **kwargs: Any):
26
+ """
27
+ Initialize the manager by creating an interface instance with the provided arguments and storing its identification.
28
+
29
+ The identification is registered with the dependency tracker for tracking purposes.
30
+ """
23
31
  self._interface = self.Interface(*args, **kwargs)
24
32
  self.__id: dict[str, Any] = self._interface.identification
25
33
  DependencyTracker.track(
@@ -33,11 +41,26 @@ class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
33
41
  return f"{self.__class__.__name__}(**{self.__id})"
34
42
 
35
43
  def __reduce__(self) -> str | tuple[Any, ...]:
44
+ """
45
+ Support object serialization by returning a tuple containing the class and identification values for pickling.
46
+ """
36
47
  return (self.__class__, tuple(self.__id.values()))
37
48
 
38
49
  def __or__(
39
- self, other: GeneralManager[GeneralManagerType] | Bucket[GeneralManagerType]
50
+ self,
51
+ other: (
52
+ GeneralManager[GeneralManagerType, InterfaceType]
53
+ | Bucket[GeneralManagerType]
54
+ ),
40
55
  ) -> Bucket[GeneralManagerType]:
56
+ """
57
+ Combine this manager with another manager of the same class or a Bucket using the union operator.
58
+
59
+ If combined with a Bucket, returns the union of the Bucket and this manager. If combined with another manager of the same class, returns a Bucket containing both instances. Raises a TypeError for unsupported types.
60
+
61
+ Returns:
62
+ Bucket[GeneralManagerType]: A Bucket containing the union of the involved managers.
63
+ """
41
64
  if isinstance(other, Bucket):
42
65
  return other | self
43
66
  elif isinstance(other, GeneralManager) and other.__class__ == self.__class__:
@@ -63,11 +86,24 @@ class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
63
86
  @dataChange
64
87
  def create(
65
88
  cls,
66
- creator_id: int,
89
+ creator_id: int | None = None,
67
90
  history_comment: str | None = None,
68
91
  ignore_permission: bool = False,
69
92
  **kwargs: dict[str, Any],
70
- ) -> GeneralManager[GeneralManagerType]:
93
+ ) -> GeneralManager[GeneralManagerType, InterfaceType]:
94
+ """
95
+ Creates a new managed object using the underlying interface and returns a corresponding manager instance.
96
+
97
+ Performs a permission check if a `Permission` class is defined and permission checks are not ignored. Passes all provided arguments to the interface's `create` method.
98
+
99
+ Parameters:
100
+ creator_id (int | None): Optional identifier for the creator of the object.
101
+ history_comment (str | None): Optional comment for audit or history tracking.
102
+ ignore_permission (bool): If True, skips the permission check.
103
+
104
+ Returns:
105
+ GeneralManager[GeneralManagerType, InterfaceType]: A new manager instance for the created object.
106
+ """
71
107
  Permission: Type[BasePermission] | None = getattr(cls, "Permission", None)
72
108
  if Permission is not None and not ignore_permission:
73
109
  Permission.checkCreatePermission(kwargs, cls, creator_id)
@@ -79,11 +115,23 @@ class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
79
115
  @dataChange
80
116
  def update(
81
117
  self,
82
- creator_id: int,
118
+ creator_id: int | None = None,
83
119
  history_comment: str | None = None,
84
120
  ignore_permission: bool = False,
85
121
  **kwargs: dict[str, Any],
86
- ) -> GeneralManager[GeneralManagerType]:
122
+ ) -> GeneralManager[GeneralManagerType, InterfaceType]:
123
+ """
124
+ Update the underlying interface object with new data and return a new manager instance.
125
+
126
+ Parameters:
127
+ creator_id (int | None): Optional identifier for the user performing the update.
128
+ history_comment (str | None): Optional comment describing the update.
129
+ ignore_permission (bool): If True, skips permission checks.
130
+ **kwargs: Additional fields to update on the interface object.
131
+
132
+ Returns:
133
+ GeneralManager[GeneralManagerType, InterfaceType]: A new manager instance reflecting the updated object.
134
+ """
87
135
  Permission: Type[BasePermission] | None = getattr(self, "Permission", None)
88
136
  if Permission is not None and not ignore_permission:
89
137
  Permission.checkUpdatePermission(kwargs, self, creator_id)
@@ -97,10 +145,21 @@ class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
97
145
  @dataChange
98
146
  def deactivate(
99
147
  self,
100
- creator_id: int,
148
+ creator_id: int | None = None,
101
149
  history_comment: str | None = None,
102
150
  ignore_permission: bool = False,
103
- ) -> GeneralManager[GeneralManagerType]:
151
+ ) -> GeneralManager[GeneralManagerType, InterfaceType]:
152
+ """
153
+ Deactivates the underlying interface object and returns a new manager instance.
154
+
155
+ Parameters:
156
+ creator_id (int | None): Optional identifier for the user performing the deactivation.
157
+ history_comment (str | None): Optional comment describing the reason for deactivation.
158
+ ignore_permission (bool): If True, skips permission checks.
159
+
160
+ Returns:
161
+ GeneralManager[GeneralManagerType, InterfaceType]: A new instance representing the deactivated object.
162
+ """
104
163
  Permission: Type[BasePermission] | None = getattr(self, "Permission", None)
105
164
  if Permission is not None and not ignore_permission:
106
165
  Permission.checkDeletePermission(self, creator_id)
@@ -130,15 +189,15 @@ class GeneralManager(Generic[GeneralManagerType], metaclass=GeneralManagerMeta):
130
189
  @staticmethod
131
190
  def __parse_identification(kwargs: dict[str, Any]) -> dict[str, Any] | None:
132
191
  """
133
- Processes a dictionary by replacing GeneralManager instances with their identifications.
192
+ Return a dictionary with all GeneralManager instances in the input replaced by their identification dictionaries.
134
193
 
135
- For each key-value pair, replaces any GeneralManager instance with its identification. Lists and tuples are processed recursively, substituting contained GeneralManager instances with their identifications. Returns None if the resulting dictionary is empty.
194
+ For each key-value pair in the input, any GeneralManager instance is replaced by its identification. Lists and tuples are processed recursively, substituting contained GeneralManager instances with their identifications. Returns None if the resulting dictionary is empty.
136
195
 
137
- Args:
138
- kwargs: Dictionary to process.
196
+ Parameters:
197
+ kwargs (dict[str, Any]): Dictionary to process.
139
198
 
140
199
  Returns:
141
- A new dictionary with GeneralManager instances replaced by their identifications, or None if empty.
200
+ dict[str, Any] | None: Processed dictionary with identifications, or None if empty.
142
201
  """
143
202
  output = {}
144
203
  for key, value in kwargs.items():
@@ -18,12 +18,12 @@ class Input(Generic[INPUT_TYPE]):
18
18
  depends_on: Optional[List[str]] = None,
19
19
  ):
20
20
  """
21
- Initializes an Input instance with type information, possible values, and dependencies.
21
+ Create an Input specification with type information, allowed values, and dependency metadata.
22
22
 
23
- Args:
24
- type: The expected type for the input value.
25
- possible_values: An optional iterable or callable that defines allowed values.
26
- depends_on: An optional list of dependency names. If not provided and possible_values is callable, dependencies are inferred from its parameters.
23
+ Parameters:
24
+ type: The expected Python type for the input value.
25
+ possible_values: Optional; an iterable of allowed values or a callable returning allowed values.
26
+ depends_on: Optional; a list of dependency names. If not provided and possible_values is callable, dependencies are inferred from the callable's parameter names.
27
27
  """
28
28
  self.type = type
29
29
  self.possible_values = possible_values
@@ -42,14 +42,9 @@ class Input(Generic[INPUT_TYPE]):
42
42
 
43
43
  def cast(self, value: Any) -> Any:
44
44
  """
45
- Casts the input value to the type specified by this Input instance.
45
+ Converts the input value to the type specified by this Input instance, handling special cases for dates, datetimes, GeneralManager subclasses, and Measurement types.
46
46
 
47
- Handles special cases for date, datetime, GeneralManager subclasses, and Measurement types.
48
- If the value is already of the target type, it is returned unchanged. Otherwise, attempts to
49
- convert or construct the value as appropriate for the target type.
50
-
51
- Args:
52
- value: The value to be cast or converted.
47
+ If the value is already of the target type, it is returned unchanged. For date and datetime types, string and cross-type conversions are supported. For GeneralManager subclasses, instances are constructed from a dictionary or an ID. For Measurement, string values are parsed accordingly. Otherwise, the value is cast using the target type's constructor.
53
48
 
54
49
  Returns:
55
50
  The value converted to the target type, or an instance of the target type.
@@ -57,6 +52,8 @@ class Input(Generic[INPUT_TYPE]):
57
52
  if self.type == date:
58
53
  if isinstance(value, datetime) and type(value) is not date:
59
54
  return value.date()
55
+ elif isinstance(value, date):
56
+ return value
60
57
  return date.fromisoformat(value)
61
58
  if self.type == datetime:
62
59
  if isinstance(value, date):
@@ -18,29 +18,30 @@ class _nonExistent:
18
18
 
19
19
  class GeneralManagerMeta(type):
20
20
  all_classes: list[Type[GeneralManager]] = []
21
- read_only_classes: list[Type[ReadOnlyInterface]] = []
21
+ read_only_classes: list[Type[GeneralManager[Any, ReadOnlyInterface]]] = []
22
22
  pending_graphql_interfaces: list[Type[GeneralManager]] = []
23
23
  pending_attribute_initialization: list[Type[GeneralManager]] = []
24
24
  Interface: type[InterfaceBase]
25
25
 
26
26
  def __new__(mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]) -> type:
27
-
28
27
  """
29
- Creates a new class, handling interface integration and registration for the general manager framework.
30
-
31
- If an 'Interface' attribute is present in the class definition, validates and processes it using the interface's pre- and post-creation hooks, then registers the resulting class for attribute initialization and tracking. If the 'AUTOCREATE_GRAPHQL' setting is enabled, also registers the class for pending GraphQL interface creation.
28
+ Create a new class using the metaclass, integrating interface hooks and registering the class for attribute initialization and tracking.
32
29
 
33
- Args:
34
- name: The name of the class being created.
35
- bases: Base classes for the new class.
36
- attrs: Attribute dictionary for the new class.
30
+ If the class definition includes an 'Interface' attribute, validates it as a subclass of `InterfaceBase`, applies pre- and post-creation hooks from the interface, and registers the resulting class for attribute initialization and management. If the `AUTOCREATE_GRAPHQL` setting is enabled, also registers the class for pending GraphQL interface creation.
37
31
 
38
32
  Returns:
39
- The newly created class, possibly augmented with interface and registration logic.
33
+ The newly created class, potentially augmented with interface integration and registration logic.
40
34
  """
35
+
41
36
  def createNewGeneralManagerClass(
42
37
  mcs, name: str, bases: tuple[type, ...], attrs: dict[str, Any]
43
38
  ) -> Type[GeneralManager]:
39
+ """
40
+ Create a new general manager class using the standard metaclass instantiation process.
41
+
42
+ Returns:
43
+ The newly created general manager class.
44
+ """
44
45
  return super().__new__(mcs, name, bases, attrs)
45
46
 
46
47
  if "Interface" in attrs:
@@ -69,6 +70,11 @@ class GeneralManagerMeta(type):
69
70
  attributes: Iterable[str], new_class: Type[GeneralManager]
70
71
  ):
71
72
 
73
+ """
74
+ Dynamically assigns property descriptors to a class for the specified attribute names.
75
+
76
+ For each attribute name, creates a descriptor that retrieves the value from an instance's `_attributes` dictionary. If accessed on the class, returns the field type from the class's interface. If the attribute is callable, it is invoked with the instance's interface. Raises `AttributeError` if the attribute is missing or if an error occurs during callable invocation.
77
+ """
72
78
  def desciptorMethod(attr_name: str, new_class: type):
73
79
  class Descriptor(Generic[GeneralManagerType]):
74
80
  def __init__(self, attr_name: str, new_class: Type[GeneralManager]):
@@ -77,7 +83,7 @@ class GeneralManagerMeta(type):
77
83
 
78
84
  def __get__(
79
85
  self,
80
- instance: GeneralManager[GeneralManagerType] | None,
86
+ instance: GeneralManager[GeneralManagerType, InterfaceBase] | None,
81
87
  owner: type | None = None,
82
88
  ):
83
89
  if instance is None:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.6.2
3
+ Version: 0.8.0
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License-Expression: MIT
@@ -1,11 +1,12 @@
1
1
  general_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- general_manager/apps.py,sha256=0QwuIAnhHm5u0wTlCiDVsl8k0RU0BEgfFjmBMl9zvsw,3320
3
- general_manager/api/graphql.py,sha256=a_mH5dvM3yXC1WyQKFCYpzSE00DQFLNKhRsZrwvLrNM,27453
4
- general_manager/api/mutation.py,sha256=uu5RVxc9wbb-Zrbtt4azegvyKymMqEsxk_CkerKCd9Q,5178
2
+ general_manager/apps.py,sha256=P_SmEPHto0Wl7cgP6l2MAOQJgXjuGBLzRIidpfHsdc0,8316
3
+ general_manager/api/graphql.py,sha256=ZMzlpgmyn2X9Zwxo12r-b5UZ2R-u1pXys_nhNczxyX8,31622
4
+ general_manager/api/mutation.py,sha256=RYCogAdUpUedyh2B9keMAzq9u-iIhEKAsoiw5xXmhrQ,5669
5
5
  general_manager/api/property.py,sha256=oc93p1P8dcIvrNorRuqD1EJVsd6eYttYhZuAS0s28gs,696
6
6
  general_manager/auxiliary/__init__.py,sha256=4IwKJzsNxGduF-Ej0u1BNHVaMhkql8PjHbVtx9DOTSY,76
7
7
  general_manager/auxiliary/argsToKwargs.py,sha256=kmp1xonpQp4X_y8ZJG6c5uOW7zQwo0HtPqsHWVzXRSM,921
8
8
  general_manager/auxiliary/filterParser.py,sha256=wmR4YzsnYgjI2Co5eyvCFROldotAraHx_GiCDJo79IY,5410
9
+ general_manager/auxiliary/formatString.py,sha256=gZSbsKvpywBmf5bIx6YW43LmNJcqsCP7ZfrB7YPvaFo,1436
9
10
  general_manager/auxiliary/jsonEncoder.py,sha256=TDsgFQvheITHZgdmn-m8tk1_QCzpT0XwEHo7bY3Qe-M,638
10
11
  general_manager/auxiliary/makeCacheKey.py,sha256=lczutqxlofLSUnheKRi8nazhOyPa04TZOFNxNn5vDu4,1126
11
12
  general_manager/auxiliary/noneToZero.py,sha256=KfQtMQnrT6vsYST0K7lv6pVujkDcK3XL8czHYOhgqKQ,539
@@ -16,7 +17,7 @@ general_manager/bucket/databaseBucket.py,sha256=V_xiPa8ErnPHVh_-i-oaH8qCa818UJxm
16
17
  general_manager/bucket/groupBucket.py,sha256=55QdUaH_qO1JFJ2Jc1f2WcxniiLE5LB3vNwbnksKk8A,10939
17
18
  general_manager/cache/cacheDecorator.py,sha256=DK2ANIJgPpMxazfMSiFrI9OuVE_7K9zlIZQRrgaC2Lw,3268
18
19
  general_manager/cache/cacheTracker.py,sha256=rRw3OhBDf86hTC2Xbt1ocRgZqwu8_kXk4lczamcADFg,2955
19
- general_manager/cache/dependencyIndex.py,sha256=kEbIAzzMzKlQgplKfcMYBPZ562zCBkOBKvJusxO_iC4,10537
20
+ general_manager/cache/dependencyIndex.py,sha256=lxD7IfnWVsBNt9l0_yDfJlHDRHAFC7N7p-Typ2tJp88,11044
20
21
  general_manager/cache/modelDependencyCollector.py,sha256=lIqBvo0QygoxxZPJ32_vMs_-eJaVJDznGyrEmxPV41E,2436
21
22
  general_manager/cache/signals.py,sha256=ZHeXKFMN7tj9t0J-vSqf_05_NhGqEF2sZtbZO3vaRqI,1234
22
23
  general_manager/factory/__init__.py,sha256=wbPIGyBlWBHa7aGWUd-1IUMPWUS-M6YqtPUL1iKXW8U,93
@@ -24,16 +25,16 @@ general_manager/factory/autoFactory.py,sha256=WBhSuMVsxkPAPLhlZhYXwHVIqiomUveS7v
24
25
  general_manager/factory/factories.py,sha256=F6_nYFyJRYYc3LQApfoVFdctfLzsWUDHKafn6xjckB8,7224
25
26
  general_manager/factory/factoryMethods.py,sha256=9Bag891j0XHe3dUBAFi7gUKcKeUwcBZN3cDLBobyBiI,3225
26
27
  general_manager/interface/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
27
- general_manager/interface/baseInterface.py,sha256=b7MH-jVADcpGluvJMogPn2O3Yiy37uCnWOM9j0Ec0o0,8692
28
+ general_manager/interface/baseInterface.py,sha256=GCMo0MGlaRAElovfI34qfuWuVYOyTQLG0OA-ZJx8i3s,8604
28
29
  general_manager/interface/calculationInterface.py,sha256=Kg_OqLw67tcLwdzYNLq31eKVLzkM7taw-8Mzmk0CYi0,4232
29
- general_manager/interface/databaseBasedInterface.py,sha256=K2PYxANuLQU8wzrajcl922tuWwko642KJAS3f3PnAmg,21566
30
- general_manager/interface/databaseInterface.py,sha256=08dFgxoLQNa13RK2NQ4cDNbNPIG-X9ChLs3NvJcSp6Y,4923
31
- general_manager/interface/readOnlyInterface.py,sha256=d2CM2gj5XZNEaVFZeNCgqZf46rwUAetVS3SyePCKNsY,4691
30
+ general_manager/interface/databaseBasedInterface.py,sha256=twdqUyvPci77WXqCX0k2dpFajhx38bbUfgxrV_BjcxQ,22788
31
+ general_manager/interface/databaseInterface.py,sha256=kYPuwjAVcVMbxozc-eg-LwGY1C0k-sqt73b7DSlVxWI,6389
32
+ general_manager/interface/readOnlyInterface.py,sha256=TkfbOeaa2wCq5kCv0a3IwJWcYOTVbtNsdNWmGAz0Mns,11217
32
33
  general_manager/manager/__init__.py,sha256=l3RYp62aEhj3Y975_XUTIzo35LUnkTJHkb_hgChnXXI,111
33
- general_manager/manager/generalManager.py,sha256=HX69KhrnSGVkuJwHY_jzff5gS0VD-6fRxKnd59A5Ct4,6100
34
+ general_manager/manager/generalManager.py,sha256=AVFZICHzqiIyn7lgPU_WLH8X8WLP1edvWAE5CljZPrk,9178
34
35
  general_manager/manager/groupManager.py,sha256=8dpZUfm7aFL4lraUWv4qbbDRClQZaYxw4prclhBZYZs,4367
35
- general_manager/manager/input.py,sha256=iKawV3P1QICz-0AQUF00OvH7LZYxussg3svpvCUl8hE,2977
36
- general_manager/manager/meta.py,sha256=g94L92hDy5gdGhgaTu3pjgZtt_fLC8LruNj9T34ApdA,4414
36
+ general_manager/manager/input.py,sha256=-pJXGJ-g2-OxZfl4Buj3mQkf05fN4p8MsR2Lh9BQcEo,3208
37
+ general_manager/manager/meta.py,sha256=gtzFKBMCvyAx5qo2BVuTBqHZzngR-ivu8YLY7oiSUEk,5059
37
38
  general_manager/measurement/__init__.py,sha256=X97meFujBldE5v0WMF7SmKeGpC5R0JTczfLo_Lq1Xek,84
38
39
  general_manager/measurement/measurement.py,sha256=e_FjHieeJbBtjXGCO9J7vRPw6KCkMrOxwWjaD0m8ee4,11777
39
40
  general_manager/measurement/measurementField.py,sha256=iq9Hqe6ZGX8CxXm4nIqTAWTRkQVptzpqE9ExX-jFyNs,5928
@@ -46,8 +47,8 @@ general_manager/permission/permissionDataManager.py,sha256=Ji7fsnuaKTa6M8yzCGyzr
46
47
  general_manager/rule/__init__.py,sha256=4Har5cfPD1fmOsilTDod-ZUz3Com-tkl58jz7yY4fD0,23
47
48
  general_manager/rule/handler.py,sha256=z8SFHTIZ0LbLh3fV56Mud0V4_OvWkqJjlHvFqau7Qfk,7334
48
49
  general_manager/rule/rule.py,sha256=3FVCKGL7BTVoStdgOTdWQwuoVRIxAIAilV4VOzouDpc,10759
49
- generalmanager-0.6.2.dist-info/licenses/LICENSE,sha256=YGFm0ieb4KpkMRRt2qnWue6uFh0cUMtobwEBkHwajhc,1450
50
- generalmanager-0.6.2.dist-info/METADATA,sha256=LpZhar2vKhlCPwavT15s1yWSeMCHH6M9rqtC69BjraQ,6205
51
- generalmanager-0.6.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
52
- generalmanager-0.6.2.dist-info/top_level.txt,sha256=sTDtExP9ga-YP3h3h42yivUY-A2Q23C2nw6LNKOho4I,16
53
- generalmanager-0.6.2.dist-info/RECORD,,
50
+ generalmanager-0.8.0.dist-info/licenses/LICENSE,sha256=YGFm0ieb4KpkMRRt2qnWue6uFh0cUMtobwEBkHwajhc,1450
51
+ generalmanager-0.8.0.dist-info/METADATA,sha256=awQ6aVm9myhb0KpGFMC_2Pc_McXqbMzECdrwxeORSkM,6205
52
+ generalmanager-0.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
53
+ generalmanager-0.8.0.dist-info/top_level.txt,sha256=sTDtExP9ga-YP3h3h42yivUY-A2Q23C2nw6LNKOho4I,16
54
+ generalmanager-0.8.0.dist-info/RECORD,,