GeneralManager 0.14.1__tar.gz → 0.15.1__tar.gz
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.
- {generalmanager-0.14.1/GeneralManager.egg-info → generalmanager-0.15.1}/PKG-INFO +10 -2
- {generalmanager-0.14.1 → generalmanager-0.15.1}/README.md +7 -1
- {generalmanager-0.14.1 → generalmanager-0.15.1}/pyproject.toml +4 -2
- {generalmanager-0.14.1 → generalmanager-0.15.1/src/GeneralManager.egg-info}/PKG-INFO +10 -2
- {generalmanager-0.14.1 → generalmanager-0.15.1/src}/GeneralManager.egg-info/SOURCES.txt +9 -5
- generalmanager-0.15.1/src/general_manager/__init__.py +49 -0
- generalmanager-0.15.1/src/general_manager/api/__init__.py +36 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/api/graphql.py +92 -43
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/api/mutation.py +35 -10
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/api/property.py +26 -3
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/apps.py +23 -16
- generalmanager-0.15.1/src/general_manager/bucket/__init__.py +32 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/bucket/baseBucket.py +76 -64
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/bucket/calculationBucket.py +188 -108
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/bucket/databaseBucket.py +130 -49
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/bucket/groupBucket.py +113 -60
- generalmanager-0.15.1/src/general_manager/cache/__init__.py +38 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/cache/cacheDecorator.py +29 -17
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/cache/cacheTracker.py +34 -15
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/cache/dependencyIndex.py +117 -33
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/cache/modelDependencyCollector.py +17 -8
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/cache/signals.py +17 -6
- generalmanager-0.15.1/src/general_manager/factory/__init__.py +34 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/factory/autoFactory.py +57 -60
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/factory/factories.py +39 -14
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/factory/factoryMethods.py +38 -1
- generalmanager-0.15.1/src/general_manager/interface/__init__.py +36 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/interface/baseInterface.py +71 -27
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/interface/calculationInterface.py +18 -10
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/interface/databaseBasedInterface.py +102 -71
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/interface/databaseInterface.py +66 -20
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/interface/models.py +10 -4
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/interface/readOnlyInterface.py +44 -30
- generalmanager-0.15.1/src/general_manager/manager/__init__.py +36 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/manager/generalManager.py +73 -47
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/manager/groupManager.py +72 -17
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/manager/input.py +23 -15
- generalmanager-0.15.1/src/general_manager/manager/meta.py +127 -0
- generalmanager-0.15.1/src/general_manager/measurement/__init__.py +37 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/measurement/measurement.py +135 -58
- generalmanager-0.15.1/src/general_manager/measurement/measurementField.py +371 -0
- generalmanager-0.15.1/src/general_manager/permission/__init__.py +32 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/permission/basePermission.py +29 -12
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/permission/managerBasedPermission.py +32 -26
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/permission/mutationPermission.py +32 -3
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/permission/permissionChecks.py +9 -1
- generalmanager-0.15.1/src/general_manager/permission/permissionDataManager.py +85 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/permission/utils.py +14 -3
- generalmanager-0.15.1/src/general_manager/rule/__init__.py +27 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/rule/handler.py +90 -5
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/rule/rule.py +40 -27
- generalmanager-0.15.1/src/general_manager/utils/__init__.py +44 -0
- generalmanager-0.15.1/src/general_manager/utils/argsToKwargs.py +33 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/utils/filterParser.py +29 -30
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/utils/formatString.py +2 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/utils/jsonEncoder.py +14 -1
- generalmanager-0.15.1/src/general_manager/utils/makeCacheKey.py +39 -0
- generalmanager-0.15.1/src/general_manager/utils/noneToZero.py +23 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/utils/pathMapping.py +92 -29
- generalmanager-0.15.1/src/general_manager/utils/public_api.py +49 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/utils/testing.py +135 -69
- generalmanager-0.14.1/src/general_manager/__init__.py +0 -0
- generalmanager-0.14.1/src/general_manager/factory/__init__.py +0 -5
- generalmanager-0.14.1/src/general_manager/interface/__init__.py +0 -0
- generalmanager-0.14.1/src/general_manager/manager/__init__.py +0 -3
- generalmanager-0.14.1/src/general_manager/manager/meta.py +0 -127
- generalmanager-0.14.1/src/general_manager/measurement/__init__.py +0 -2
- generalmanager-0.14.1/src/general_manager/measurement/measurementField.py +0 -271
- generalmanager-0.14.1/src/general_manager/permission/__init__.py +0 -1
- generalmanager-0.14.1/src/general_manager/permission/permissionDataManager.py +0 -51
- generalmanager-0.14.1/src/general_manager/rule/__init__.py +0 -1
- generalmanager-0.14.1/src/general_manager/utils/__init__.py +0 -2
- generalmanager-0.14.1/src/general_manager/utils/argsToKwargs.py +0 -25
- generalmanager-0.14.1/src/general_manager/utils/makeCacheKey.py +0 -33
- generalmanager-0.14.1/src/general_manager/utils/noneToZero.py +0 -21
- {generalmanager-0.14.1 → generalmanager-0.15.1}/LICENSE +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/setup.cfg +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1/src}/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1/src}/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1/src}/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/src/general_manager/permission/fileBasedPermission.py +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/tests/test_settings.py +0 -0
- {generalmanager-0.14.1 → generalmanager-0.15.1}/tests/test_urls.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: GeneralManager
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.15.1
|
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: MIT License
|
@@ -26,7 +26,9 @@ License: MIT License
|
|
26
26
|
SOFTWARE.
|
27
27
|
Classifier: License :: OSI Approved :: MIT License
|
28
28
|
Classifier: Programming Language :: Python :: 3
|
29
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
29
30
|
Classifier: Programming Language :: Python :: 3.12
|
31
|
+
Classifier: Programming Language :: Python :: 3.13
|
30
32
|
Classifier: Framework :: Django
|
31
33
|
Classifier: Intended Audience :: Developers
|
32
34
|
Classifier: Operating System :: OS Independent
|
@@ -63,6 +65,12 @@ Dynamic: license-file
|
|
63
65
|
|
64
66
|
# GeneralManager
|
65
67
|
|
68
|
+
[](https://pypi.org/project/GeneralManager/)
|
69
|
+
[](https://pypi.org/project/GeneralManager/)
|
70
|
+
[](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml)
|
71
|
+
[](https://app.codecov.io/gh/TimKleindick/general_manager)
|
72
|
+
[](LICENSE)
|
73
|
+
|
66
74
|
## Overview
|
67
75
|
|
68
76
|
GeneralManager is a powerful and flexible framework designed for managing and processing data. It provides a modular structure that enables developers to implement complex business logic efficiently. The module is written entirely in Python and uses Django as the backend framework.
|
@@ -202,4 +210,4 @@ query {
|
|
202
210
|
|
203
211
|
## License
|
204
212
|
|
205
|
-
This project is distributed under the **
|
213
|
+
This project is distributed under the **MIT License**. For further details see the [LICENSE](./LICENSE) file.
|
@@ -1,5 +1,11 @@
|
|
1
1
|
# GeneralManager
|
2
2
|
|
3
|
+
[](https://pypi.org/project/GeneralManager/)
|
4
|
+
[](https://pypi.org/project/GeneralManager/)
|
5
|
+
[](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml)
|
6
|
+
[](https://app.codecov.io/gh/TimKleindick/general_manager)
|
7
|
+
[](LICENSE)
|
8
|
+
|
3
9
|
## Overview
|
4
10
|
|
5
11
|
GeneralManager is a powerful and flexible framework designed for managing and processing data. It provides a modular structure that enables developers to implement complex business logic efficiently. The module is written entirely in Python and uses Django as the backend framework.
|
@@ -139,4 +145,4 @@ query {
|
|
139
145
|
|
140
146
|
## License
|
141
147
|
|
142
|
-
This project is distributed under the **
|
148
|
+
This project is distributed under the **MIT License**. For further details see the [LICENSE](./LICENSE) file.
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "GeneralManager"
|
7
|
-
version = "0.
|
7
|
+
version = "0.15.1"
|
8
8
|
description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
|
9
9
|
readme = "README.md"
|
10
10
|
authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
|
@@ -12,7 +12,9 @@ license = { file = "LICENSE" }
|
|
12
12
|
classifiers = [
|
13
13
|
"License :: OSI Approved :: MIT License",
|
14
14
|
"Programming Language :: Python :: 3",
|
15
|
+
"Programming Language :: Python :: 3 :: Only",
|
15
16
|
"Programming Language :: Python :: 3.12",
|
17
|
+
"Programming Language :: Python :: 3.13",
|
16
18
|
"Framework :: Django",
|
17
19
|
"Intended Audience :: Developers",
|
18
20
|
"Operating System :: OS Independent",
|
@@ -48,7 +50,7 @@ dependencies = [
|
|
48
50
|
]
|
49
51
|
|
50
52
|
[tool.setuptools.packages.find]
|
51
|
-
where = ["src"
|
53
|
+
where = ["src"]
|
52
54
|
|
53
55
|
[tool.semantic_release]
|
54
56
|
allow_zero_version = true
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: GeneralManager
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.15.1
|
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: MIT License
|
@@ -26,7 +26,9 @@ License: MIT License
|
|
26
26
|
SOFTWARE.
|
27
27
|
Classifier: License :: OSI Approved :: MIT License
|
28
28
|
Classifier: Programming Language :: Python :: 3
|
29
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
29
30
|
Classifier: Programming Language :: Python :: 3.12
|
31
|
+
Classifier: Programming Language :: Python :: 3.13
|
30
32
|
Classifier: Framework :: Django
|
31
33
|
Classifier: Intended Audience :: Developers
|
32
34
|
Classifier: Operating System :: OS Independent
|
@@ -63,6 +65,12 @@ Dynamic: license-file
|
|
63
65
|
|
64
66
|
# GeneralManager
|
65
67
|
|
68
|
+
[](https://pypi.org/project/GeneralManager/)
|
69
|
+
[](https://pypi.org/project/GeneralManager/)
|
70
|
+
[](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml)
|
71
|
+
[](https://app.codecov.io/gh/TimKleindick/general_manager)
|
72
|
+
[](LICENSE)
|
73
|
+
|
66
74
|
## Overview
|
67
75
|
|
68
76
|
GeneralManager is a powerful and flexible framework designed for managing and processing data. It provides a modular structure that enables developers to implement complex business logic efficiently. The module is written entirely in Python and uses Django as the backend framework.
|
@@ -202,4 +210,4 @@ query {
|
|
202
210
|
|
203
211
|
## License
|
204
212
|
|
205
|
-
This project is distributed under the **
|
213
|
+
This project is distributed under the **MIT License**. For further details see the [LICENSE](./LICENSE) file.
|
@@ -1,20 +1,23 @@
|
|
1
1
|
LICENSE
|
2
2
|
README.md
|
3
3
|
pyproject.toml
|
4
|
-
GeneralManager.egg-info/PKG-INFO
|
5
|
-
GeneralManager.egg-info/SOURCES.txt
|
6
|
-
GeneralManager.egg-info/dependency_links.txt
|
7
|
-
GeneralManager.egg-info/requires.txt
|
8
|
-
GeneralManager.egg-info/top_level.txt
|
4
|
+
src/GeneralManager.egg-info/PKG-INFO
|
5
|
+
src/GeneralManager.egg-info/SOURCES.txt
|
6
|
+
src/GeneralManager.egg-info/dependency_links.txt
|
7
|
+
src/GeneralManager.egg-info/requires.txt
|
8
|
+
src/GeneralManager.egg-info/top_level.txt
|
9
9
|
src/general_manager/__init__.py
|
10
10
|
src/general_manager/apps.py
|
11
|
+
src/general_manager/api/__init__.py
|
11
12
|
src/general_manager/api/graphql.py
|
12
13
|
src/general_manager/api/mutation.py
|
13
14
|
src/general_manager/api/property.py
|
15
|
+
src/general_manager/bucket/__init__.py
|
14
16
|
src/general_manager/bucket/baseBucket.py
|
15
17
|
src/general_manager/bucket/calculationBucket.py
|
16
18
|
src/general_manager/bucket/databaseBucket.py
|
17
19
|
src/general_manager/bucket/groupBucket.py
|
20
|
+
src/general_manager/cache/__init__.py
|
18
21
|
src/general_manager/cache/cacheDecorator.py
|
19
22
|
src/general_manager/cache/cacheTracker.py
|
20
23
|
src/general_manager/cache/dependencyIndex.py
|
@@ -58,6 +61,7 @@ src/general_manager/utils/jsonEncoder.py
|
|
58
61
|
src/general_manager/utils/makeCacheKey.py
|
59
62
|
src/general_manager/utils/noneToZero.py
|
60
63
|
src/general_manager/utils/pathMapping.py
|
64
|
+
src/general_manager/utils/public_api.py
|
61
65
|
src/general_manager/utils/testing.py
|
62
66
|
tests/test_settings.py
|
63
67
|
tests/test_urls.py
|
@@ -0,0 +1,49 @@
|
|
1
|
+
"""Convenience access to GeneralManager core components."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from general_manager.utils.public_api import build_module_dir, resolve_export
|
8
|
+
|
9
|
+
__all__ = [
|
10
|
+
"GraphQL",
|
11
|
+
"GeneralManager",
|
12
|
+
"GeneralManagerMeta",
|
13
|
+
"Input",
|
14
|
+
"graphQlProperty",
|
15
|
+
"graphQlMutation",
|
16
|
+
"Bucket",
|
17
|
+
"DatabaseBucket",
|
18
|
+
"CalculationBucket",
|
19
|
+
"GroupBucket",
|
20
|
+
]
|
21
|
+
|
22
|
+
_MODULE_MAP = {
|
23
|
+
"GraphQL": ("general_manager.api.graphql", "GraphQL"),
|
24
|
+
"graphQlProperty": ("general_manager.api.property", "graphQlProperty"),
|
25
|
+
"graphQlMutation": ("general_manager.api.mutation", "graphQlMutation"),
|
26
|
+
"GeneralManager": ("general_manager.manager.generalManager", "GeneralManager"),
|
27
|
+
"GeneralManagerMeta": ("general_manager.manager.meta", "GeneralManagerMeta"),
|
28
|
+
"Input": ("general_manager.manager.input", "Input"),
|
29
|
+
"Bucket": ("general_manager.bucket.baseBucket", "Bucket"),
|
30
|
+
"DatabaseBucket": ("general_manager.bucket.databaseBucket", "DatabaseBucket"),
|
31
|
+
"CalculationBucket": (
|
32
|
+
"general_manager.bucket.calculationBucket",
|
33
|
+
"CalculationBucket",
|
34
|
+
),
|
35
|
+
"GroupBucket": ("general_manager.bucket.groupBucket", "GroupBucket"),
|
36
|
+
}
|
37
|
+
|
38
|
+
|
39
|
+
def __getattr__(name: str) -> Any:
|
40
|
+
return resolve_export(
|
41
|
+
name,
|
42
|
+
module_all=__all__,
|
43
|
+
module_map=_MODULE_MAP,
|
44
|
+
module_globals=globals(),
|
45
|
+
)
|
46
|
+
|
47
|
+
|
48
|
+
def __dir__() -> list[str]:
|
49
|
+
return build_module_dir(module_all=__all__, module_globals=globals())
|
@@ -0,0 +1,36 @@
|
|
1
|
+
"""GraphQL helpers for GeneralManager."""
|
2
|
+
|
3
|
+
from __future__ import annotations
|
4
|
+
|
5
|
+
from typing import Any
|
6
|
+
|
7
|
+
from general_manager.utils.public_api import build_module_dir, resolve_export
|
8
|
+
|
9
|
+
__all__ = [
|
10
|
+
"GraphQL",
|
11
|
+
"MeasurementType",
|
12
|
+
"MeasurementScalar",
|
13
|
+
"graphQlProperty",
|
14
|
+
"graphQlMutation",
|
15
|
+
]
|
16
|
+
|
17
|
+
_MODULE_MAP = {
|
18
|
+
"GraphQL": ("general_manager.api.graphql", "GraphQL"),
|
19
|
+
"MeasurementType": ("general_manager.api.graphql", "MeasurementType"),
|
20
|
+
"MeasurementScalar": ("general_manager.api.graphql", "MeasurementScalar"),
|
21
|
+
"graphQlProperty": ("general_manager.api.property", "graphQlProperty"),
|
22
|
+
"graphQlMutation": ("general_manager.api.mutation", "graphQlMutation"),
|
23
|
+
}
|
24
|
+
|
25
|
+
|
26
|
+
def __getattr__(name: str) -> Any:
|
27
|
+
return resolve_export(
|
28
|
+
name,
|
29
|
+
module_all=__all__,
|
30
|
+
module_map=_MODULE_MAP,
|
31
|
+
module_globals=globals(),
|
32
|
+
)
|
33
|
+
|
34
|
+
|
35
|
+
def __dir__() -> list[str]:
|
36
|
+
return build_module_dir(module_all=__all__, module_globals=globals())
|
@@ -1,5 +1,7 @@
|
|
1
|
+
"""GraphQL schema utilities for exposing GeneralManager models via Graphene."""
|
2
|
+
|
1
3
|
from __future__ import annotations
|
2
|
-
import graphene
|
4
|
+
import graphene # type: ignore[import]
|
3
5
|
from typing import (
|
4
6
|
Any,
|
5
7
|
Callable,
|
@@ -73,9 +75,14 @@ def getReadPermissionFilter(
|
|
73
75
|
info: GraphQLResolveInfo,
|
74
76
|
) -> list[tuple[dict[str, Any], dict[str, Any]]]:
|
75
77
|
"""
|
76
|
-
|
78
|
+
Return permission-derived filter and exclude pairs for the given manager class.
|
79
|
+
|
80
|
+
Parameters:
|
81
|
+
generalManagerClass (GeneralManagerMeta): Manager class being queried.
|
82
|
+
info (GraphQLResolveInfo): GraphQL resolver info containing the request user.
|
77
83
|
|
78
|
-
|
84
|
+
Returns:
|
85
|
+
list[tuple[dict[str, Any], dict[str, Any]]]: List of ``(filter, exclude)`` mappings.
|
79
86
|
"""
|
80
87
|
filters = []
|
81
88
|
PermissionClass: type[BasePermission] | None = getattr(
|
@@ -93,10 +100,7 @@ def getReadPermissionFilter(
|
|
93
100
|
|
94
101
|
|
95
102
|
class GraphQL:
|
96
|
-
"""
|
97
|
-
Baut die GraphQL-Oberfläche auf und erstellt Resolver-Funktionen
|
98
|
-
dynamisch für die angegebene GeneralManager-Klasse.
|
99
|
-
"""
|
103
|
+
"""Static helper that builds GraphQL types, queries, and mutations for managers."""
|
100
104
|
|
101
105
|
_query_class: type[graphene.ObjectType] | None = None
|
102
106
|
_mutation_class: type[graphene.ObjectType] | None = None
|
@@ -109,16 +113,17 @@ class GraphQL:
|
|
109
113
|
@classmethod
|
110
114
|
def createGraphqlMutation(cls, generalManagerClass: type[GeneralManager]) -> None:
|
111
115
|
"""
|
112
|
-
|
116
|
+
Register create, update, and delete mutations for ``generalManagerClass``.
|
113
117
|
|
114
|
-
|
118
|
+
Parameters:
|
119
|
+
generalManagerClass (type[GeneralManager]): Manager class whose interface drives mutation generation.
|
115
120
|
"""
|
116
121
|
|
117
122
|
interface_cls: InterfaceBase | None = getattr(
|
118
123
|
generalManagerClass, "Interface", None
|
119
124
|
)
|
120
125
|
if not interface_cls:
|
121
|
-
return
|
126
|
+
return None
|
122
127
|
|
123
128
|
default_return_values = {
|
124
129
|
"success": graphene.Boolean(),
|
@@ -147,15 +152,16 @@ class GraphQL:
|
|
147
152
|
@classmethod
|
148
153
|
def createGraphqlInterface(cls, generalManagerClass: GeneralManagerMeta) -> None:
|
149
154
|
"""
|
150
|
-
|
155
|
+
Build and register a Graphene ``ObjectType`` for the supplied manager class.
|
151
156
|
|
152
|
-
|
157
|
+
Parameters:
|
158
|
+
generalManagerClass (GeneralManagerMeta): Manager class whose attributes drive field generation.
|
153
159
|
"""
|
154
160
|
interface_cls: InterfaceBase | None = getattr(
|
155
161
|
generalManagerClass, "Interface", None
|
156
162
|
)
|
157
163
|
if not interface_cls:
|
158
|
-
return
|
164
|
+
return None
|
159
165
|
|
160
166
|
graphene_type_name = f"{generalManagerClass.__name__}Type"
|
161
167
|
fields: dict[str, Any] = {}
|
@@ -217,10 +223,13 @@ class GraphQL:
|
|
217
223
|
generalManagerClass: GeneralManagerMeta,
|
218
224
|
) -> type[graphene.Enum] | None:
|
219
225
|
"""
|
220
|
-
|
226
|
+
Build an enum of sortable fields for the provided manager class.
|
227
|
+
|
228
|
+
Parameters:
|
229
|
+
generalManagerClass (GeneralManagerMeta): Manager class being inspected.
|
221
230
|
|
222
231
|
Returns:
|
223
|
-
|
232
|
+
type[graphene.Enum] | None: Enum of sortable fields, or ``None`` when no options exist.
|
224
233
|
"""
|
225
234
|
sort_options = []
|
226
235
|
for (
|
@@ -264,6 +273,16 @@ class GraphQL:
|
|
264
273
|
None,
|
265
274
|
None,
|
266
275
|
]:
|
276
|
+
"""
|
277
|
+
Yield filter field names and Graphene types for a given attribute.
|
278
|
+
|
279
|
+
Parameters:
|
280
|
+
attribute_type (type): Python type declared for the attribute.
|
281
|
+
attribute_name (str): Name of the attribute.
|
282
|
+
|
283
|
+
Yields:
|
284
|
+
tuple[str, Graphene type | None]: Filter name and corresponding Graphene type.
|
285
|
+
"""
|
267
286
|
number_options = ["exact", "gt", "gte", "lt", "lte"]
|
268
287
|
string_options = [
|
269
288
|
"exact",
|
@@ -306,22 +325,20 @@ class GraphQL:
|
|
306
325
|
field_type: GeneralManagerMeta,
|
307
326
|
) -> type[graphene.InputObjectType] | None:
|
308
327
|
"""
|
309
|
-
|
310
|
-
|
311
|
-
Creates filter fields for each attribute based on its type, supporting numeric and string filter operations, and specialized handling for Measurement attributes. Returns the generated InputObjectType, or None if no applicable filter fields exist.
|
328
|
+
Create a Graphene ``InputObjectType`` for filters on ``field_type``.
|
312
329
|
|
313
330
|
Parameters:
|
314
|
-
field_type (GeneralManagerMeta):
|
331
|
+
field_type (GeneralManagerMeta): Manager class whose attributes drive filter generation.
|
315
332
|
|
316
333
|
Returns:
|
317
|
-
type[graphene.InputObjectType] | None:
|
334
|
+
type[graphene.InputObjectType] | None: Input type containing filter fields, or ``None`` if not applicable.
|
318
335
|
"""
|
319
336
|
|
320
337
|
graphene_filter_type_name = f"{field_type.__name__}FilterType"
|
321
338
|
if graphene_filter_type_name in GraphQL.graphql_filter_type_registry:
|
322
339
|
return GraphQL.graphql_filter_type_registry[graphene_filter_type_name]
|
323
340
|
|
324
|
-
filter_fields = {}
|
341
|
+
filter_fields: dict[str, Any] = {}
|
325
342
|
for attr_name, attr_info in field_type.Interface.getAttributeTypes().items():
|
326
343
|
attr_type = attr_info["type"]
|
327
344
|
filter_fields = {
|
@@ -360,9 +377,14 @@ class GraphQL:
|
|
360
377
|
@staticmethod
|
361
378
|
def _mapFieldToGrapheneRead(field_type: type, field_name: str) -> Any:
|
362
379
|
"""
|
363
|
-
|
380
|
+
Map a field type and name to the appropriate Graphene field for reads.
|
364
381
|
|
365
|
-
|
382
|
+
Parameters:
|
383
|
+
field_type (type): Python type declared on the interface.
|
384
|
+
field_name (str): Attribute name being exposed.
|
385
|
+
|
386
|
+
Returns:
|
387
|
+
Any: Graphene field or type configured for the attribute.
|
366
388
|
"""
|
367
389
|
if issubclass(field_type, Measurement):
|
368
390
|
return graphene.Field(MeasurementType, target_unit=graphene.String())
|
@@ -398,7 +420,13 @@ class GraphQL:
|
|
398
420
|
@staticmethod
|
399
421
|
def _mapFieldToGrapheneBaseType(field_type: type) -> Type[Any]:
|
400
422
|
"""
|
401
|
-
|
423
|
+
Map a Python type to the corresponding Graphene scalar/class.
|
424
|
+
|
425
|
+
Parameters:
|
426
|
+
field_type (type): Python type declared on the interface.
|
427
|
+
|
428
|
+
Returns:
|
429
|
+
Type[Any]: Graphene scalar or type implementing the field.
|
402
430
|
"""
|
403
431
|
if issubclass(field_type, dict):
|
404
432
|
raise TypeError("GraphQL does not support dict fields")
|
@@ -422,7 +450,13 @@ class GraphQL:
|
|
422
450
|
@staticmethod
|
423
451
|
def _parseInput(input_val: dict[str, Any] | str | None) -> dict[str, Any]:
|
424
452
|
"""
|
425
|
-
|
453
|
+
Normalise filter/exclude input into a dictionary.
|
454
|
+
|
455
|
+
Parameters:
|
456
|
+
input_val (dict[str, Any] | str | None): Raw filter/exclude value.
|
457
|
+
|
458
|
+
Returns:
|
459
|
+
dict[str, Any]: Parsed dictionary suitable for queryset filtering.
|
426
460
|
"""
|
427
461
|
if input_val is None:
|
428
462
|
return {}
|
@@ -474,10 +508,15 @@ class GraphQL:
|
|
474
508
|
info: GraphQLResolveInfo,
|
475
509
|
) -> Bucket:
|
476
510
|
"""
|
477
|
-
|
511
|
+
Apply permission-based filters to ``queryset`` for the current user.
|
512
|
+
|
513
|
+
Parameters:
|
514
|
+
queryset (Bucket): Queryset being filtered.
|
515
|
+
general_manager_class (type[GeneralManager]): Manager class providing permissions.
|
516
|
+
info (GraphQLResolveInfo): Resolver info containing the request user.
|
478
517
|
|
479
518
|
Returns:
|
480
|
-
|
519
|
+
Bucket: Queryset constrained by read permissions.
|
481
520
|
"""
|
482
521
|
permission_filters = getReadPermissionFilter(general_manager_class, info)
|
483
522
|
if not permission_filters:
|
@@ -494,9 +533,7 @@ class GraphQL:
|
|
494
533
|
def _checkReadPermission(
|
495
534
|
instance: GeneralManager, info: GraphQLResolveInfo, field_name: str
|
496
535
|
) -> bool:
|
497
|
-
"""
|
498
|
-
Überprüft, ob der Benutzer Lesezugriff auf das jeweilige Feld hat.
|
499
|
-
"""
|
536
|
+
"""Return True if the user may read ``field_name`` on ``instance``."""
|
500
537
|
PermissionClass: type[BasePermission] | None = getattr(
|
501
538
|
instance, "Permission", None
|
502
539
|
)
|
@@ -511,9 +548,14 @@ class GraphQL:
|
|
511
548
|
base_getter: Callable[[Any], Any], fallback_manager_class: type[GeneralManager]
|
512
549
|
) -> Callable[..., Any]:
|
513
550
|
"""
|
514
|
-
|
551
|
+
Build a resolver for list fields applying filters, permissions, and paging.
|
515
552
|
|
516
|
-
|
553
|
+
Parameters:
|
554
|
+
base_getter (Callable[[Any], Any]): Callable returning the base queryset.
|
555
|
+
fallback_manager_class (type[GeneralManager]): Manager used when ``base_getter`` returns ``None``.
|
556
|
+
|
557
|
+
Returns:
|
558
|
+
Callable[..., Any]: Resolver function compatible with Graphene.
|
517
559
|
"""
|
518
560
|
|
519
561
|
def resolver(
|
@@ -691,9 +733,11 @@ class GraphQL:
|
|
691
733
|
cls, graphene_type: type, generalManagerClass: GeneralManagerMeta
|
692
734
|
) -> None:
|
693
735
|
"""
|
694
|
-
|
736
|
+
Register list and detail query fields for ``generalManagerClass``.
|
695
737
|
|
696
|
-
|
738
|
+
Parameters:
|
739
|
+
graphene_type (type): Graphene ``ObjectType`` representing the manager.
|
740
|
+
generalManagerClass (GeneralManagerMeta): Manager class being exposed.
|
697
741
|
"""
|
698
742
|
if not issubclass(generalManagerClass, GeneralManager):
|
699
743
|
raise TypeError(
|
@@ -701,7 +745,7 @@ class GraphQL:
|
|
701
745
|
)
|
702
746
|
|
703
747
|
if not hasattr(cls, "_query_fields"):
|
704
|
-
cls._query_fields
|
748
|
+
cls._query_fields = cast(dict[str, Any], {})
|
705
749
|
|
706
750
|
# resolver and field for the list query
|
707
751
|
list_field_name = f"{generalManagerClass.__name__.lower()}_list"
|
@@ -761,12 +805,13 @@ class GraphQL:
|
|
761
805
|
@classmethod
|
762
806
|
def createWriteFields(cls, interface_cls: InterfaceBase) -> dict[str, Any]:
|
763
807
|
"""
|
764
|
-
|
808
|
+
Generate Graphene input fields for writable interface attributes.
|
765
809
|
|
766
|
-
|
810
|
+
Parameters:
|
811
|
+
interface_cls (InterfaceBase): Interface whose attributes drive the input field map.
|
767
812
|
|
768
813
|
Returns:
|
769
|
-
dict[str, Any]: Mapping of attribute names to Graphene
|
814
|
+
dict[str, Any]: Mapping of attribute names to Graphene field definitions.
|
770
815
|
"""
|
771
816
|
fields: dict[str, Any] = {}
|
772
817
|
|
@@ -827,7 +872,7 @@ class GraphQL:
|
|
827
872
|
generalManagerClass, "Interface", None
|
828
873
|
)
|
829
874
|
if not interface_cls:
|
830
|
-
return
|
875
|
+
return None
|
831
876
|
|
832
877
|
def create_mutation(
|
833
878
|
self,
|
@@ -898,7 +943,7 @@ class GraphQL:
|
|
898
943
|
generalManagerClass, "Interface", None
|
899
944
|
)
|
900
945
|
if not interface_cls:
|
901
|
-
return
|
946
|
+
return None
|
902
947
|
|
903
948
|
def update_mutation(
|
904
949
|
self,
|
@@ -975,7 +1020,7 @@ class GraphQL:
|
|
975
1020
|
generalManagerClass, "Interface", None
|
976
1021
|
)
|
977
1022
|
if not interface_cls:
|
978
|
-
return
|
1023
|
+
return None
|
979
1024
|
|
980
1025
|
def delete_mutation(
|
981
1026
|
self,
|
@@ -1030,9 +1075,13 @@ class GraphQL:
|
|
1030
1075
|
@staticmethod
|
1031
1076
|
def _handleGraphQLError(error: Exception) -> None:
|
1032
1077
|
"""
|
1033
|
-
|
1078
|
+
Raise a ``GraphQLError`` with a code based on the exception type.
|
1079
|
+
|
1080
|
+
Parameters:
|
1081
|
+
error (Exception): Exception raised during mutation execution.
|
1034
1082
|
|
1035
|
-
|
1083
|
+
Raises:
|
1084
|
+
GraphQLError: Error with an appropriate ``extensions['code']`` value.
|
1036
1085
|
"""
|
1037
1086
|
if isinstance(error, PermissionError):
|
1038
1087
|
raise GraphQLError(
|
@@ -1,15 +1,21 @@
|
|
1
|
+
"""Decorator utilities for building GraphQL mutations from manager functions."""
|
2
|
+
|
1
3
|
import inspect
|
2
4
|
from typing import (
|
3
|
-
|
5
|
+
Callable,
|
4
6
|
Optional,
|
7
|
+
TypeVar,
|
5
8
|
Union,
|
6
9
|
List,
|
7
10
|
Tuple,
|
8
11
|
get_origin,
|
9
12
|
get_args,
|
10
13
|
Type,
|
14
|
+
get_type_hints,
|
15
|
+
cast,
|
11
16
|
)
|
12
|
-
import graphene
|
17
|
+
import graphene # type: ignore[import]
|
18
|
+
from graphql import GraphQLResolveInfo
|
13
19
|
|
14
20
|
from general_manager.api.graphql import GraphQL
|
15
21
|
from general_manager.manager.generalManager import GeneralManager
|
@@ -19,7 +25,13 @@ from typing import TypeAliasType
|
|
19
25
|
from general_manager.permission.mutationPermission import MutationPermission
|
20
26
|
|
21
27
|
|
22
|
-
|
28
|
+
FuncT = TypeVar("FuncT", bound=Callable[..., object])
|
29
|
+
|
30
|
+
|
31
|
+
def graphQlMutation(
|
32
|
+
_func: FuncT | type[MutationPermission] | None = None,
|
33
|
+
permission: Optional[Type[MutationPermission]] = None,
|
34
|
+
) -> FuncT | Callable[[FuncT], FuncT]:
|
23
35
|
"""
|
24
36
|
Decorator that converts a function into a GraphQL mutation class for use with Graphene, automatically generating argument and output fields from the function's signature and type annotations.
|
25
37
|
|
@@ -39,11 +51,15 @@ def graphQlMutation(_func=None, permission: Optional[Type[MutationPermission]] =
|
|
39
51
|
permission = _func
|
40
52
|
_func = None
|
41
53
|
|
42
|
-
def decorator(fn):
|
54
|
+
def decorator(fn: FuncT) -> FuncT:
|
43
55
|
"""
|
44
|
-
|
56
|
+
Transform ``fn`` into a Graphene-compatible mutation class.
|
57
|
+
|
58
|
+
Parameters:
|
59
|
+
fn (Callable[..., Any]): Resolver implementing the mutation behaviour.
|
45
60
|
|
46
|
-
|
61
|
+
Returns:
|
62
|
+
Callable[..., Any]: Original function after registration.
|
47
63
|
"""
|
48
64
|
sig = inspect.signature(fn)
|
49
65
|
hints = get_type_hints(fn)
|
@@ -128,12 +144,21 @@ def graphQlMutation(_func=None, permission: Optional[Type[MutationPermission]] =
|
|
128
144
|
)
|
129
145
|
|
130
146
|
# Define mutate method
|
131
|
-
def _mutate(
|
147
|
+
def _mutate(
|
148
|
+
root: object,
|
149
|
+
info: GraphQLResolveInfo,
|
150
|
+
**kwargs: object,
|
151
|
+
) -> graphene.Mutation:
|
132
152
|
"""
|
133
|
-
|
153
|
+
Execute the mutation resolver, enforcing permissions and formatting output.
|
154
|
+
|
155
|
+
Parameters:
|
156
|
+
root: Graphene root object (unused).
|
157
|
+
info: GraphQL execution info passed by Graphene.
|
158
|
+
**kwargs: Mutation arguments provided by the client.
|
134
159
|
|
135
160
|
Returns:
|
136
|
-
|
161
|
+
mutation_class: Instance populated with resolver results and a success flag.
|
137
162
|
"""
|
138
163
|
if permission:
|
139
164
|
permission.check(kwargs, info.context.user)
|
@@ -176,5 +201,5 @@ def graphQlMutation(_func=None, permission: Optional[Type[MutationPermission]] =
|
|
176
201
|
return fn
|
177
202
|
|
178
203
|
if _func is not None and inspect.isfunction(_func):
|
179
|
-
return decorator(_func)
|
204
|
+
return decorator(cast(FuncT, _func))
|
180
205
|
return decorator
|