GeneralManager 0.14.0__tar.gz → 0.15.0__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.
Files changed (84) hide show
  1. generalmanager-0.15.0/LICENSE +21 -0
  2. {generalmanager-0.14.0/GeneralManager.egg-info → generalmanager-0.15.0}/PKG-INFO +38 -4
  3. {generalmanager-0.14.0 → generalmanager-0.15.0}/README.md +7 -1
  4. {generalmanager-0.14.0 → generalmanager-0.15.0}/pyproject.toml +14 -5
  5. {generalmanager-0.14.0 → generalmanager-0.15.0/src/GeneralManager.egg-info}/PKG-INFO +38 -4
  6. {generalmanager-0.14.0 → generalmanager-0.15.0/src}/GeneralManager.egg-info/SOURCES.txt +9 -5
  7. {generalmanager-0.14.0 → generalmanager-0.15.0/src}/GeneralManager.egg-info/requires.txt +1 -1
  8. generalmanager-0.15.0/src/general_manager/__init__.py +49 -0
  9. generalmanager-0.15.0/src/general_manager/api/__init__.py +36 -0
  10. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/api/graphql.py +92 -43
  11. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/api/mutation.py +35 -10
  12. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/api/property.py +26 -3
  13. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/apps.py +23 -16
  14. generalmanager-0.15.0/src/general_manager/bucket/__init__.py +32 -0
  15. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/bucket/baseBucket.py +76 -64
  16. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/bucket/calculationBucket.py +188 -108
  17. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/bucket/databaseBucket.py +130 -49
  18. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/bucket/groupBucket.py +113 -60
  19. generalmanager-0.15.0/src/general_manager/cache/__init__.py +38 -0
  20. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/cache/cacheDecorator.py +29 -17
  21. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/cache/cacheTracker.py +34 -15
  22. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/cache/dependencyIndex.py +117 -33
  23. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/cache/modelDependencyCollector.py +17 -8
  24. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/cache/signals.py +17 -6
  25. generalmanager-0.15.0/src/general_manager/factory/__init__.py +34 -0
  26. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/factory/autoFactory.py +57 -60
  27. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/factory/factories.py +39 -14
  28. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/factory/factoryMethods.py +38 -1
  29. generalmanager-0.15.0/src/general_manager/interface/__init__.py +36 -0
  30. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/interface/baseInterface.py +71 -27
  31. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/interface/calculationInterface.py +18 -10
  32. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/interface/databaseBasedInterface.py +102 -71
  33. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/interface/databaseInterface.py +66 -20
  34. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/interface/models.py +10 -4
  35. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/interface/readOnlyInterface.py +44 -30
  36. generalmanager-0.15.0/src/general_manager/manager/__init__.py +36 -0
  37. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/manager/generalManager.py +73 -47
  38. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/manager/groupManager.py +72 -17
  39. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/manager/input.py +23 -15
  40. generalmanager-0.15.0/src/general_manager/manager/meta.py +127 -0
  41. generalmanager-0.15.0/src/general_manager/measurement/__init__.py +37 -0
  42. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/measurement/measurement.py +135 -58
  43. generalmanager-0.15.0/src/general_manager/measurement/measurementField.py +371 -0
  44. generalmanager-0.15.0/src/general_manager/permission/__init__.py +32 -0
  45. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/permission/basePermission.py +29 -12
  46. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/permission/managerBasedPermission.py +32 -26
  47. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/permission/mutationPermission.py +32 -3
  48. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/permission/permissionChecks.py +9 -1
  49. generalmanager-0.15.0/src/general_manager/permission/permissionDataManager.py +85 -0
  50. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/permission/utils.py +14 -3
  51. generalmanager-0.15.0/src/general_manager/rule/__init__.py +27 -0
  52. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/rule/handler.py +90 -5
  53. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/rule/rule.py +40 -27
  54. generalmanager-0.15.0/src/general_manager/utils/__init__.py +44 -0
  55. generalmanager-0.15.0/src/general_manager/utils/argsToKwargs.py +33 -0
  56. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/utils/filterParser.py +29 -30
  57. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/utils/formatString.py +2 -0
  58. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/utils/jsonEncoder.py +14 -1
  59. generalmanager-0.15.0/src/general_manager/utils/makeCacheKey.py +39 -0
  60. generalmanager-0.15.0/src/general_manager/utils/noneToZero.py +23 -0
  61. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/utils/pathMapping.py +92 -29
  62. generalmanager-0.15.0/src/general_manager/utils/public_api.py +49 -0
  63. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/utils/testing.py +135 -69
  64. generalmanager-0.14.0/LICENSE +0 -29
  65. generalmanager-0.14.0/src/general_manager/__init__.py +0 -0
  66. generalmanager-0.14.0/src/general_manager/factory/__init__.py +0 -5
  67. generalmanager-0.14.0/src/general_manager/interface/__init__.py +0 -0
  68. generalmanager-0.14.0/src/general_manager/manager/__init__.py +0 -3
  69. generalmanager-0.14.0/src/general_manager/manager/meta.py +0 -127
  70. generalmanager-0.14.0/src/general_manager/measurement/__init__.py +0 -2
  71. generalmanager-0.14.0/src/general_manager/measurement/measurementField.py +0 -271
  72. generalmanager-0.14.0/src/general_manager/permission/__init__.py +0 -1
  73. generalmanager-0.14.0/src/general_manager/permission/permissionDataManager.py +0 -51
  74. generalmanager-0.14.0/src/general_manager/rule/__init__.py +0 -1
  75. generalmanager-0.14.0/src/general_manager/utils/__init__.py +0 -2
  76. generalmanager-0.14.0/src/general_manager/utils/argsToKwargs.py +0 -25
  77. generalmanager-0.14.0/src/general_manager/utils/makeCacheKey.py +0 -33
  78. generalmanager-0.14.0/src/general_manager/utils/noneToZero.py +0 -21
  79. {generalmanager-0.14.0 → generalmanager-0.15.0}/setup.cfg +0 -0
  80. {generalmanager-0.14.0 → generalmanager-0.15.0/src}/GeneralManager.egg-info/dependency_links.txt +0 -0
  81. {generalmanager-0.14.0 → generalmanager-0.15.0/src}/GeneralManager.egg-info/top_level.txt +0 -0
  82. {generalmanager-0.14.0 → generalmanager-0.15.0}/src/general_manager/permission/fileBasedPermission.py +0 -0
  83. {generalmanager-0.14.0 → generalmanager-0.15.0}/tests/test_settings.py +0 -0
  84. {generalmanager-0.14.0 → generalmanager-0.15.0}/tests/test_urls.py +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Tim Kleindick
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,14 +1,42 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.14.0
3
+ Version: 0.15.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
- License-Expression: MIT
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Tim Kleindick
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Classifier: License :: OSI Approved :: MIT License
28
+ Classifier: Programming Language :: Python :: 3
29
+ Classifier: Programming Language :: Python :: 3 :: Only
30
+ Classifier: Programming Language :: Python :: 3.12
31
+ Classifier: Programming Language :: Python :: 3.13
32
+ Classifier: Framework :: Django
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Operating System :: OS Independent
7
35
  Requires-Python: >=3.12
8
36
  Description-Content-Type: text/markdown
9
37
  License-File: LICENSE
10
38
  Requires-Dist: asgiref>=3.8.1
11
- Requires-Dist: Django>=5.2
39
+ Requires-Dist: Django>=5.2.7
12
40
  Requires-Dist: django-simple-history>=3.8.0
13
41
  Requires-Dist: exrex>=0.12.0
14
42
  Requires-Dist: factory_boy>=3.3.3
@@ -37,6 +65,12 @@ Dynamic: license-file
37
65
 
38
66
  # GeneralManager
39
67
 
68
+ [![PyPI](https://img.shields.io/pypi/v/GeneralManager.svg)](https://pypi.org/project/GeneralManager/)
69
+ [![Python](https://img.shields.io/pypi/pyversions/GeneralManager.svg)](https://pypi.org/project/GeneralManager/)
70
+ [![Build](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml)
71
+ [![Coverage](https://img.shields.io/codecov/c/github/TimKleindick/general_manager)](https://app.codecov.io/gh/TimKleindick/general_manager)
72
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
73
+
40
74
  ## Overview
41
75
 
42
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.
@@ -176,4 +210,4 @@ query {
176
210
 
177
211
  ## License
178
212
 
179
- This project is distributed under the **Non-Commercial MIT License**. It may only be used for non-commercial purposes. For further details see the [LICENSE](./LICENSE) file.
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
+ [![PyPI](https://img.shields.io/pypi/v/GeneralManager.svg)](https://pypi.org/project/GeneralManager/)
4
+ [![Python](https://img.shields.io/pypi/pyversions/GeneralManager.svg)](https://pypi.org/project/GeneralManager/)
5
+ [![Build](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml)
6
+ [![Coverage](https://img.shields.io/codecov/c/github/TimKleindick/general_manager)](https://app.codecov.io/gh/TimKleindick/general_manager)
7
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](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 **Non-Commercial MIT License**. It may only be used for non-commercial purposes. For further details see the [LICENSE](./LICENSE) file.
148
+ This project is distributed under the **MIT License**. For further details see the [LICENSE](./LICENSE) file.
@@ -4,16 +4,25 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GeneralManager"
7
- version = "0.14.0"
7
+ version = "0.15.0"
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" }]
11
- license = "MIT"
12
- license-files = ["LICENSE"]
11
+ license = { file = "LICENSE" }
12
+ classifiers = [
13
+ "License :: OSI Approved :: MIT License",
14
+ "Programming Language :: Python :: 3",
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Framework :: Django",
19
+ "Intended Audience :: Developers",
20
+ "Operating System :: OS Independent",
21
+ ]
13
22
  requires-python = ">=3.12"
14
23
  dependencies = [
15
24
  "asgiref>=3.8.1",
16
- "Django>=5.2",
25
+ "Django>=5.2.7",
17
26
  "django-simple-history>=3.8.0",
18
27
  "exrex>=0.12.0",
19
28
  "factory_boy>=3.3.3",
@@ -41,7 +50,7 @@ dependencies = [
41
50
  ]
42
51
 
43
52
  [tool.setuptools.packages.find]
44
- where = ["src", "general_manager"]
53
+ where = ["src"]
45
54
 
46
55
  [tool.semantic_release]
47
56
  allow_zero_version = true
@@ -1,14 +1,42 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.14.0
3
+ Version: 0.15.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
- License-Expression: MIT
6
+ License: MIT License
7
+
8
+ Copyright (c) 2025 Tim Kleindick
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+ Classifier: License :: OSI Approved :: MIT License
28
+ Classifier: Programming Language :: Python :: 3
29
+ Classifier: Programming Language :: Python :: 3 :: Only
30
+ Classifier: Programming Language :: Python :: 3.12
31
+ Classifier: Programming Language :: Python :: 3.13
32
+ Classifier: Framework :: Django
33
+ Classifier: Intended Audience :: Developers
34
+ Classifier: Operating System :: OS Independent
7
35
  Requires-Python: >=3.12
8
36
  Description-Content-Type: text/markdown
9
37
  License-File: LICENSE
10
38
  Requires-Dist: asgiref>=3.8.1
11
- Requires-Dist: Django>=5.2
39
+ Requires-Dist: Django>=5.2.7
12
40
  Requires-Dist: django-simple-history>=3.8.0
13
41
  Requires-Dist: exrex>=0.12.0
14
42
  Requires-Dist: factory_boy>=3.3.3
@@ -37,6 +65,12 @@ Dynamic: license-file
37
65
 
38
66
  # GeneralManager
39
67
 
68
+ [![PyPI](https://img.shields.io/pypi/v/GeneralManager.svg)](https://pypi.org/project/GeneralManager/)
69
+ [![Python](https://img.shields.io/pypi/pyversions/GeneralManager.svg)](https://pypi.org/project/GeneralManager/)
70
+ [![Build](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/TimKleindick/general_manager/actions/workflows/test.yml)
71
+ [![Coverage](https://img.shields.io/codecov/c/github/TimKleindick/general_manager)](https://app.codecov.io/gh/TimKleindick/general_manager)
72
+ [![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
73
+
40
74
  ## Overview
41
75
 
42
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.
@@ -176,4 +210,4 @@ query {
176
210
 
177
211
  ## License
178
212
 
179
- This project is distributed under the **Non-Commercial MIT License**. It may only be used for non-commercial purposes. For further details see the [LICENSE](./LICENSE) file.
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
@@ -1,5 +1,5 @@
1
1
  asgiref>=3.8.1
2
- Django>=5.2
2
+ Django>=5.2.7
3
3
  django-simple-history>=3.8.0
4
4
  exrex>=0.12.0
5
5
  factory_boy>=3.3.3
@@ -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
- Returns permission-based filter and exclude constraints for querying instances of a manager class.
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
- For the given manager class and user context, retrieves a list of (filter, exclude) dictionary pairs that represent the read access restrictions to be applied to queries. Returns an empty list if no permission class is defined.
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
- Generates and registers GraphQL mutation classes for create, update, and delete operations on the specified manager class if its interface provides custom implementations.
116
+ Register create, update, and delete mutations for ``generalManagerClass``.
113
117
 
114
- For each supported mutation, a corresponding GraphQL mutation class is created and added to the mutation registry, enabling dynamic mutation support in the schema.
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
- Creates and registers a GraphQL ObjectType for a GeneralManager subclass.
155
+ Build and register a Graphene ``ObjectType`` for the supplied manager class.
151
156
 
152
- Introspects the manager's interface and GraphQLProperty fields, maps them to Graphene fields with appropriate resolvers, registers the resulting type in the internal registry, and adds corresponding query fields to the schema.
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
- Creates a Graphene Enum type representing sortable fields for a given GeneralManager class.
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
- A Graphene Enum type with options for each sortable attribute, including separate entries for the value and unit of Measurement fields. Returns None if there are no sortable fields.
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
- Dynamically generates a Graphene InputObjectType for filtering fields of a GeneralManager subclass.
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): The manager class whose attributes are used to build filter fields.
331
+ field_type (GeneralManagerMeta): Manager class whose attributes drive filter generation.
315
332
 
316
333
  Returns:
317
- type[graphene.InputObjectType] | None: The generated filter input type, or None if no filter fields are applicable.
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
- Maps a Python field type and name to the appropriate Graphene field for GraphQL schema generation.
380
+ Map a field type and name to the appropriate Graphene field for reads.
364
381
 
365
- For `Measurement` fields, returns a Graphene field with an optional `target_unit` argument. For `GeneralManager` subclasses, returns a paginated field with filtering, exclusion, sorting, pagination, and grouping arguments if the field name ends with `_list`; otherwise, returns a single object field. For all other types, returns the corresponding Graphene scalar field.
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
- Ordnet einen Python-Typ einem entsprechenden Graphene-Feld zu.
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
- Wandelt einen als JSON-String oder Dict gelieferten Filter/Exclude-Parameter in ein Dict um.
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
- Applies permission-based filters to a queryset according to the permission interface of the given manager class.
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
- A queryset containing only the items allowed by the user's read permissions. If no permission filters are defined, returns the original queryset unchanged.
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
- Creates a resolver for GraphQL list fields that returns paginated, filtered, sorted, and optionally grouped results with permission checks.
551
+ Build a resolver for list fields applying filters, permissions, and paging.
515
552
 
516
- The generated resolver applies permission-based filtering, user-specified filters and exclusions, sorting, grouping, and pagination to the list field. It returns a dictionary containing the resulting items and pagination metadata.
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
- Adds paginated list and single-item query fields for a GeneralManager subclass to the GraphQL schema.
736
+ Register list and detail query fields for ``generalManagerClass``.
695
737
 
696
- The list query field enables filtering, exclusion, sorting, pagination, and grouping, returning a paginated result with metadata. The single-item query field retrieves an instance by its identification fields. Both queries are registered with their respective resolvers.
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: dict[str, Any] = {}
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
- Generates a dictionary of Graphene input fields for mutations based on the attributes of the provided interface class.
808
+ Generate Graphene input fields for writable interface attributes.
765
809
 
766
- Skips system-managed and derived attributes. For attributes referencing `GeneralManager` subclasses, uses an ID or list of IDs as appropriate. Other types are mapped to their corresponding Graphene scalar types. Each field is annotated with an `editable` attribute. Always includes an optional `history_comment` field marked as editable.
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 input fields for mutation arguments.
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
- Raises a GraphQLError with a specific error code based on the exception type.
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
- PermissionError results in "PERMISSION_DENIED", ValueError or ValidationError in "BAD_USER_INPUT", and all other exceptions in "INTERNAL_SERVER_ERROR".
1083
+ Raises:
1084
+ GraphQLError: Error with an appropriate ``extensions['code']`` value.
1036
1085
  """
1037
1086
  if isinstance(error, PermissionError):
1038
1087
  raise GraphQLError(