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.
Files changed (43) hide show
  1. general_manager/__init__.py +0 -0
  2. general_manager/api/graphql.py +732 -0
  3. general_manager/api/mutation.py +143 -0
  4. general_manager/api/property.py +20 -0
  5. general_manager/apps.py +83 -0
  6. general_manager/auxiliary/__init__.py +2 -0
  7. general_manager/auxiliary/argsToKwargs.py +25 -0
  8. general_manager/auxiliary/filterParser.py +97 -0
  9. general_manager/auxiliary/noneToZero.py +12 -0
  10. general_manager/cache/cacheDecorator.py +72 -0
  11. general_manager/cache/cacheTracker.py +33 -0
  12. general_manager/cache/dependencyIndex.py +300 -0
  13. general_manager/cache/pathMapping.py +151 -0
  14. general_manager/cache/signals.py +48 -0
  15. general_manager/factory/__init__.py +5 -0
  16. general_manager/factory/factories.py +287 -0
  17. general_manager/factory/lazy_methods.py +38 -0
  18. general_manager/interface/__init__.py +3 -0
  19. general_manager/interface/baseInterface.py +308 -0
  20. general_manager/interface/calculationInterface.py +406 -0
  21. general_manager/interface/databaseInterface.py +726 -0
  22. general_manager/manager/__init__.py +3 -0
  23. general_manager/manager/generalManager.py +136 -0
  24. general_manager/manager/groupManager.py +288 -0
  25. general_manager/manager/input.py +48 -0
  26. general_manager/manager/meta.py +75 -0
  27. general_manager/measurement/__init__.py +2 -0
  28. general_manager/measurement/measurement.py +233 -0
  29. general_manager/measurement/measurementField.py +152 -0
  30. general_manager/permission/__init__.py +1 -0
  31. general_manager/permission/basePermission.py +178 -0
  32. general_manager/permission/fileBasedPermission.py +0 -0
  33. general_manager/permission/managerBasedPermission.py +171 -0
  34. general_manager/permission/permissionChecks.py +53 -0
  35. general_manager/permission/permissionDataManager.py +55 -0
  36. general_manager/rule/__init__.py +1 -0
  37. general_manager/rule/handler.py +122 -0
  38. general_manager/rule/rule.py +313 -0
  39. generalmanager-0.0.0.dist-info/METADATA +207 -0
  40. generalmanager-0.0.0.dist-info/RECORD +43 -0
  41. generalmanager-0.0.0.dist-info/WHEEL +5 -0
  42. generalmanager-0.0.0.dist-info/licenses/LICENSE +29 -0
  43. generalmanager-0.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,171 @@
1
+ from __future__ import annotations
2
+ from typing import TYPE_CHECKING, Literal, Optional, Dict
3
+ from general_manager.permission.basePermission import BasePermission
4
+
5
+ if TYPE_CHECKING:
6
+ from general_manager.permission.permissionDataManager import (
7
+ PermissionDataManager,
8
+ )
9
+ from general_manager.manager.generalManager import GeneralManager
10
+ from django.contrib.auth.models import AbstractUser
11
+
12
+ type permission_type = Literal[
13
+ "create",
14
+ "read",
15
+ "update",
16
+ "delete",
17
+ ]
18
+
19
+
20
+ class ManagerBasedPermission(BasePermission):
21
+ __based_on__: Optional[str] = None
22
+ __read__: list[str] = ["public"]
23
+ __create__: list[str] = ["isAuthenticated"]
24
+ __update__: list[str] = ["isAuthenticated"]
25
+ __delete__: list[str] = ["isAuthenticated"]
26
+
27
+ def __init__(
28
+ self,
29
+ instance: PermissionDataManager | GeneralManager,
30
+ request_user: AbstractUser,
31
+ ) -> None:
32
+
33
+ self.__instance = instance
34
+ self.__request_user = request_user
35
+ self.__attribute_permissions = self.__getAttributePermissions()
36
+ self.__based_on_permission = self.__getBasedOnPermission()
37
+ self.__overall_results: Dict[permission_type, Optional[bool]] = {
38
+ "create": None,
39
+ "read": None,
40
+ "update": None,
41
+ "delete": None,
42
+ }
43
+
44
+ def __getBasedOnPermission(self) -> Optional[BasePermission]:
45
+ from general_manager.manager.generalManager import GeneralManager
46
+
47
+ __based_on__ = getattr(self, "__based_on__")
48
+ if __based_on__ is None:
49
+ return None
50
+
51
+ basis_object = getattr(self.instance, __based_on__, None)
52
+ if basis_object is None:
53
+ raise ValueError(
54
+ f"Based on object {__based_on__} not found in instance {self.__instance}"
55
+ )
56
+ if not isinstance(basis_object, GeneralManager) and not issubclass(
57
+ basis_object, GeneralManager
58
+ ):
59
+ raise TypeError(f"Based on object {__based_on__} is not a GeneralManager")
60
+
61
+ Permission = getattr(basis_object, "Permission", None)
62
+
63
+ if Permission is None or not issubclass(
64
+ Permission,
65
+ BasePermission,
66
+ ):
67
+ return None
68
+
69
+ return Permission(
70
+ instance=getattr(self.instance, __based_on__),
71
+ request_user=self.request_user,
72
+ )
73
+
74
+ @property
75
+ def instance(self) -> PermissionDataManager | GeneralManager:
76
+ return self.__instance
77
+
78
+ @property
79
+ def request_user(self) -> AbstractUser:
80
+ return self.__request_user
81
+
82
+ def __getAttributePermissions(
83
+ self,
84
+ ) -> dict[str, dict[permission_type, list[str]]]:
85
+ attribute_permissions = {}
86
+ for attribute in self.__class__.__dict__:
87
+ if not attribute.startswith("__"):
88
+ attribute_permissions[attribute] = getattr(self, attribute)
89
+ return attribute_permissions
90
+
91
+ def checkPermission(
92
+ self,
93
+ action: permission_type,
94
+ attriubte: str,
95
+ ) -> bool:
96
+ if (
97
+ self.__based_on_permission
98
+ and not self.__based_on_permission.checkPermission(action, attriubte)
99
+ ):
100
+ return False
101
+
102
+ if action == "create":
103
+ permissions = self.__create__
104
+ elif action == "read":
105
+ permissions = self.__read__
106
+ elif action == "update":
107
+ permissions = self.__update__
108
+ elif action == "delete":
109
+ permissions = self.__delete__
110
+ else:
111
+ raise ValueError(f"Action {action} not found")
112
+
113
+ has_attribute_permissions = (
114
+ attriubte in self.__attribute_permissions
115
+ and action in self.__attribute_permissions[attriubte]
116
+ )
117
+
118
+ if not has_attribute_permissions:
119
+ last_result = self.__overall_results.get(action)
120
+ if last_result is not None:
121
+ return last_result
122
+ attribute_permission = True
123
+ else:
124
+ attribute_permission = self.__checkSpecificPermission(
125
+ self.__attribute_permissions[attriubte][action]
126
+ )
127
+
128
+ permission = self.__checkSpecificPermission(permissions)
129
+ self.__overall_results[action] = permission
130
+ return permission and attribute_permission
131
+
132
+ def __checkSpecificPermission(
133
+ self,
134
+ permissions: list[str],
135
+ ) -> bool:
136
+ for permission in permissions:
137
+ if self.validatePermissionString(permission):
138
+ return True
139
+ return False
140
+
141
+ def getPermissionFilter(
142
+ self,
143
+ ) -> list[dict[Literal["filter", "exclude"], dict[str, str]]]:
144
+ """
145
+ Returns the filter for the permission
146
+ """
147
+ __based_on__ = getattr(self, "__based_on__")
148
+ filters: list[dict[Literal["filter", "exclude"], dict[str, str]]] = []
149
+
150
+ if self.__based_on_permission is not None:
151
+ base_permissions = self.__based_on_permission.getPermissionFilter()
152
+ for permission in base_permissions:
153
+ filter = permission.get("filter", {})
154
+ exclude = permission.get("exclude", {})
155
+ filters.append(
156
+ {
157
+ "filter": {
158
+ f"{__based_on__}__{key}": value
159
+ for key, value in filter.items()
160
+ },
161
+ "exclude": {
162
+ f"{__based_on__}__{key}": value
163
+ for key, value in exclude.items()
164
+ },
165
+ }
166
+ )
167
+
168
+ for permission in self.__read__:
169
+ filters.append(self._getPermissionFilter(permission))
170
+
171
+ return filters
@@ -0,0 +1,53 @@
1
+ from typing import Any, Callable, TYPE_CHECKING, TypedDict, Literal
2
+
3
+ if TYPE_CHECKING:
4
+ from django.contrib.auth.models import AbstractUser, AnonymousUser
5
+ from general_manager.permission.permissionDataManager import (
6
+ PermissionDataManager,
7
+ )
8
+ from general_manager.manager.generalManager import GeneralManager
9
+ from general_manager.manager.meta import GeneralManagerMeta
10
+
11
+
12
+ type permission_filter = Callable[
13
+ [AbstractUser | AnonymousUser, list[str]],
14
+ dict[Literal["filter", "exclude"], dict[str, str]] | None,
15
+ ]
16
+
17
+ type permission_method = Callable[
18
+ [
19
+ PermissionDataManager | GeneralManager | GeneralManagerMeta,
20
+ AbstractUser | AnonymousUser,
21
+ list[str],
22
+ ],
23
+ bool,
24
+ ]
25
+
26
+
27
+ class PermissionDict(TypedDict):
28
+ permission_method: permission_method
29
+ permission_filter: permission_filter
30
+
31
+
32
+ permission_functions: dict[str, PermissionDict] = {
33
+ "public": {
34
+ "permission_method": lambda instance, user, config: True,
35
+ "permission_filter": lambda user, config: None,
36
+ },
37
+ "ends_with": {
38
+ "permission_method": lambda instance, user, config: getattr(
39
+ instance, config[0]
40
+ ).endswith(config[1]),
41
+ "permission_filter": lambda user, config: {
42
+ "filter": {f"{config[0]}__endswith": config[1]}
43
+ },
44
+ },
45
+ "admin": {
46
+ "permission_method": lambda instance, user, config: user.is_staff,
47
+ "permission_filter": lambda user, config: None,
48
+ },
49
+ "isAuthenticated": {
50
+ "permission_method": lambda instance, user, config: user.is_authenticated,
51
+ "permission_filter": lambda user, config: None,
52
+ },
53
+ }
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+ from typing import Callable, Dict, Any, Optional, TypeVar, Generic
3
+ from django.contrib.auth.models import AbstractUser
4
+
5
+ from general_manager.manager.generalManager import GeneralManager
6
+
7
+ GeneralManagerData = TypeVar("GeneralManagerData", bound=GeneralManager)
8
+
9
+
10
+ class PermissionDataManager(Generic[GeneralManagerData]):
11
+ def __init__(
12
+ self,
13
+ permission_data: Dict[str, Any] | GeneralManagerData,
14
+ manager: Optional[type[GeneralManagerData]] = None,
15
+ ):
16
+ self.getData: Callable[[str], Any]
17
+ self._permission_data = permission_data
18
+ if isinstance(permission_data, GeneralManager):
19
+ self.getData = lambda name, permission_data=permission_data: getattr(
20
+ permission_data, name
21
+ )
22
+ self._manager = permission_data.__class__
23
+ elif isinstance(permission_data, dict):
24
+ self.getData = (
25
+ lambda name, permission_data=permission_data: permission_data.get(name)
26
+ )
27
+ if manager is None:
28
+ raise ValueError(
29
+ "Manager must be provided if permission_data is a dict"
30
+ )
31
+ self._manager = manager
32
+ else:
33
+ raise TypeError(
34
+ "permission_data must be either a dict or an instance of GeneralManager"
35
+ )
36
+
37
+ @classmethod
38
+ def forUpdate(
39
+ cls,
40
+ base_data: GeneralManagerData,
41
+ update_data: Dict[str, Any],
42
+ ) -> PermissionDataManager:
43
+ merged_data = {**dict(base_data), **update_data}
44
+ return cls(merged_data, base_data.__class__)
45
+
46
+ @property
47
+ def permission_data(self) -> Dict[str, Any] | GeneralManagerData:
48
+ return self._permission_data
49
+
50
+ @property
51
+ def manager(self) -> type[GeneralManagerData]:
52
+ return self._manager
53
+
54
+ def __getattr__(self, name: str) -> Any:
55
+ return self.getData(name)
@@ -0,0 +1 @@
1
+ from .rule import Rule
@@ -0,0 +1,122 @@
1
+ # generalManager/src/rule/handlers.py
2
+
3
+ from __future__ import annotations
4
+ import ast
5
+ from typing import Dict, Optional, TYPE_CHECKING, cast
6
+
7
+ if TYPE_CHECKING:
8
+ # Forward-Reference auf Rule mit beliebigem Generic-Parameter
9
+ from general_manager.rule.rule import Rule
10
+ from general_manager.manager import GeneralManager
11
+
12
+
13
+ class BaseRuleHandler:
14
+ """Schnittstelle für Rule-Handler."""
15
+
16
+ function_name: str # ClassVar, der Name, unter dem dieser Handler registriert wird
17
+
18
+ def handle(
19
+ self,
20
+ node: ast.AST,
21
+ left: Optional[ast.expr],
22
+ right: Optional[ast.expr],
23
+ op: Optional[ast.cmpop],
24
+ var_values: Dict[str, Optional[object]],
25
+ rule: Rule,
26
+ ) -> Dict[str, str]:
27
+ """
28
+ Erstelle Fehlermeldungen für den Vergleichs- oder Funktionsaufruf.
29
+ """
30
+ raise NotImplementedError
31
+
32
+
33
+ class LenHandler(BaseRuleHandler):
34
+ function_name = "len"
35
+
36
+ def handle(
37
+ self,
38
+ node: ast.AST,
39
+ left: Optional[ast.expr],
40
+ right: Optional[ast.expr],
41
+ op: Optional[ast.cmpop],
42
+ var_values: Dict[str, Optional[object]],
43
+ rule: Rule,
44
+ ) -> Dict[str, str]:
45
+ # Wir erwarten hier einen Compare-Knoten
46
+ if not isinstance(node, ast.Compare):
47
+ return {}
48
+ compare_node = node
49
+
50
+ left_node = compare_node.left
51
+ right_node = compare_node.comparators[0]
52
+ op_symbol = rule._get_op_symbol(op)
53
+
54
+ # Argument von len(...)
55
+ if not (isinstance(left_node, ast.Call) and left_node.args):
56
+ raise ValueError("Invalid left node for len function")
57
+ arg_node = left_node.args[0]
58
+
59
+ var_name = rule._get_node_name(arg_node)
60
+ var_value = var_values.get(var_name)
61
+
62
+ # --- Hier der Typ-Guard für right_value ---
63
+ raw = rule._eval_node(right_node)
64
+ if not isinstance(raw, (int, float)):
65
+ raise ValueError("Invalid arguments for len function")
66
+ right_value: int | float = raw
67
+
68
+ # Schwellenwert je nach Operator
69
+ if op_symbol == ">":
70
+ threshold = right_value + 1
71
+ elif op_symbol == ">=":
72
+ threshold = right_value
73
+ elif op_symbol == "<":
74
+ threshold = right_value - 1
75
+ elif op_symbol == "<=":
76
+ threshold = right_value
77
+ else:
78
+ threshold = right_value
79
+
80
+ # Fehlermeldung formulieren
81
+ if op_symbol in (">", ">="):
82
+ msg = f"[{var_name}] ({var_value}) is too short (min length {threshold})!"
83
+ elif op_symbol in ("<", "<="):
84
+ msg = f"[{var_name}] ({var_value}) is too long (max length {threshold})!"
85
+ else:
86
+ msg = f"[{var_name}] ({var_value}) must be {op_symbol} {right_value}!"
87
+
88
+ return {var_name: msg}
89
+
90
+
91
+ class IntersectionCheckHandler(BaseRuleHandler):
92
+ function_name = "intersectionCheck"
93
+
94
+ def handle(
95
+ self,
96
+ node: ast.AST,
97
+ left: Optional[ast.expr],
98
+ right: Optional[ast.expr],
99
+ op: Optional[ast.cmpop],
100
+ var_values: Dict[str, Optional[object]],
101
+ rule: Rule[GeneralManager],
102
+ ) -> Dict[str, str]:
103
+ # Der Aufruf steht in `left`, nicht in `node`
104
+ call_node = cast(ast.Call, left)
105
+ if not isinstance(call_node, ast.Call):
106
+ return {"error": "Invalid arguments for intersectionCheck"}
107
+
108
+ args = call_node.args
109
+ if len(args) < 2:
110
+ return {"error": "Invalid arguments for intersectionCheck"}
111
+
112
+ start_node, end_node = args[0], args[1]
113
+ start_name = rule._get_node_name(start_node)
114
+ end_name = rule._get_node_name(end_node)
115
+ start_val = var_values.get(start_name)
116
+ end_val = var_values.get(end_name)
117
+
118
+ msg = (
119
+ f"[{start_name}] ({start_val}) and "
120
+ f"[{end_name}] ({end_val}) must not overlap with existing ranges."
121
+ )
122
+ return {start_name: msg, end_name: msg}