GeneralManager 0.19.1__py3-none-any.whl → 0.20.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.

Potentially problematic release.


This version of GeneralManager might be problematic. Click here for more details.

Files changed (64) hide show
  1. general_manager/_types/api.py +4 -4
  2. general_manager/_types/bucket.py +4 -4
  3. general_manager/_types/cache.py +6 -6
  4. general_manager/_types/factory.py +35 -35
  5. general_manager/_types/general_manager.py +11 -9
  6. general_manager/_types/interface.py +5 -5
  7. general_manager/_types/manager.py +4 -4
  8. general_manager/_types/measurement.py +1 -1
  9. general_manager/_types/permission.py +3 -3
  10. general_manager/_types/utils.py +12 -12
  11. general_manager/api/graphql.py +207 -98
  12. general_manager/api/mutation.py +9 -9
  13. general_manager/api/property.py +4 -4
  14. general_manager/apps.py +120 -65
  15. general_manager/bucket/{baseBucket.py → base_bucket.py} +5 -5
  16. general_manager/bucket/{calculationBucket.py → calculation_bucket.py} +10 -10
  17. general_manager/bucket/{databaseBucket.py → database_bucket.py} +16 -19
  18. general_manager/bucket/{groupBucket.py → group_bucket.py} +8 -8
  19. general_manager/cache/{cacheDecorator.py → cache_decorator.py} +27 -6
  20. general_manager/cache/{cacheTracker.py → cache_tracker.py} +1 -1
  21. general_manager/cache/{dependencyIndex.py → dependency_index.py} +24 -8
  22. general_manager/cache/{modelDependencyCollector.py → model_dependency_collector.py} +4 -4
  23. general_manager/cache/signals.py +1 -1
  24. general_manager/factory/{autoFactory.py → auto_factory.py} +24 -19
  25. general_manager/factory/factories.py +10 -13
  26. general_manager/factory/{factoryMethods.py → factory_methods.py} +19 -17
  27. general_manager/interface/{baseInterface.py → base_interface.py} +30 -22
  28. general_manager/interface/{calculationInterface.py → calculation_interface.py} +10 -10
  29. general_manager/interface/{databaseBasedInterface.py → database_based_interface.py} +42 -42
  30. general_manager/interface/{databaseInterface.py → database_interface.py} +21 -21
  31. general_manager/interface/models.py +3 -3
  32. general_manager/interface/{readOnlyInterface.py → read_only_interface.py} +34 -25
  33. general_manager/logging.py +133 -0
  34. general_manager/manager/{generalManager.py → general_manager.py} +75 -17
  35. general_manager/manager/{groupManager.py → group_manager.py} +6 -6
  36. general_manager/manager/input.py +1 -1
  37. general_manager/manager/meta.py +63 -17
  38. general_manager/measurement/measurement.py +3 -3
  39. general_manager/permission/{basePermission.py → base_permission.py} +55 -32
  40. general_manager/permission/{managerBasedPermission.py → manager_based_permission.py} +21 -21
  41. general_manager/permission/{mutationPermission.py → mutation_permission.py} +12 -12
  42. general_manager/permission/{permissionChecks.py → permission_checks.py} +2 -2
  43. general_manager/permission/{permissionDataManager.py → permission_data_manager.py} +6 -6
  44. general_manager/permission/utils.py +6 -6
  45. general_manager/public_api_registry.py +76 -66
  46. general_manager/rule/handler.py +2 -2
  47. general_manager/rule/rule.py +102 -11
  48. general_manager/utils/{filterParser.py → filter_parser.py} +3 -3
  49. general_manager/utils/{jsonEncoder.py → json_encoder.py} +1 -1
  50. general_manager/utils/{makeCacheKey.py → make_cache_key.py} +1 -1
  51. general_manager/utils/{noneToZero.py → none_to_zero.py} +1 -1
  52. general_manager/utils/{pathMapping.py → path_mapping.py} +14 -14
  53. general_manager/utils/public_api.py +19 -0
  54. general_manager/utils/testing.py +14 -14
  55. {generalmanager-0.19.1.dist-info → generalmanager-0.20.0.dist-info}/METADATA +1 -1
  56. generalmanager-0.20.0.dist-info/RECORD +78 -0
  57. generalmanager-0.19.1.dist-info/RECORD +0 -77
  58. /general_manager/measurement/{measurementField.py → measurement_field.py} +0 -0
  59. /general_manager/permission/{fileBasedPermission.py → file_based_permission.py} +0 -0
  60. /general_manager/utils/{argsToKwargs.py → args_to_kwargs.py} +0 -0
  61. /general_manager/utils/{formatString.py → format_string.py} +0 -0
  62. {generalmanager-0.19.1.dist-info → generalmanager-0.20.0.dist-info}/WHEEL +0 -0
  63. {generalmanager-0.19.1.dist-info → generalmanager-0.20.0.dist-info}/licenses/LICENSE +0 -0
  64. {generalmanager-0.19.1.dist-info → generalmanager-0.20.0.dist-info}/top_level.txt +0 -0
@@ -20,10 +20,10 @@ import graphene # type: ignore[import]
20
20
  from graphql import GraphQLResolveInfo
21
21
 
22
22
  from general_manager.api.graphql import GraphQL, HANDLED_MANAGER_ERRORS
23
- from general_manager.manager.generalManager import GeneralManager
23
+ from general_manager.manager.general_manager import GeneralManager
24
24
 
25
- from general_manager.utils.formatString import snake_to_camel
26
- from general_manager.permission.mutationPermission import MutationPermission
25
+ from general_manager.utils.format_string import snake_to_camel
26
+ from general_manager.permission.mutation_permission import MutationPermission
27
27
  from types import UnionType
28
28
 
29
29
 
@@ -91,7 +91,7 @@ class DuplicateMutationOutputNameError(ValueError):
91
91
  )
92
92
 
93
93
 
94
- def graphQlMutation(
94
+ def graph_ql_mutation(
95
95
  _func: FuncT | type[MutationPermission] | None = None,
96
96
  permission: Optional[Type[MutationPermission]] = None,
97
97
  ) -> FuncT | Callable[[FuncT], FuncT]:
@@ -162,14 +162,14 @@ def graphQlMutation(
162
162
  if get_origin(ann) is list or get_origin(ann) is List:
163
163
  inner = get_args(ann)[0]
164
164
  field = graphene.List(
165
- GraphQL._mapFieldToGrapheneBaseType(inner),
165
+ GraphQL._map_field_to_graphene_base_type(inner),
166
166
  **kwargs,
167
167
  )
168
168
  else:
169
169
  if inspect.isclass(ann) and issubclass(ann, GeneralManager):
170
170
  field = graphene.ID(**kwargs)
171
171
  else:
172
- field = GraphQL._mapFieldToGrapheneBaseType(ann)(**kwargs)
172
+ field = GraphQL._map_field_to_graphene_base_type(ann)(**kwargs)
173
173
 
174
174
  arg_fields[name] = field
175
175
 
@@ -201,7 +201,7 @@ def graphQlMutation(
201
201
 
202
202
  basis_type = out.__value__ if is_named_type else out
203
203
 
204
- outputs[field_name] = GraphQL._mapFieldToGrapheneRead(
204
+ outputs[field_name] = GraphQL._map_field_to_graphene_read(
205
205
  basis_type, field_name
206
206
  )
207
207
 
@@ -220,7 +220,7 @@ def graphQlMutation(
220
220
  **kwargs: Mutation arguments provided by the client.
221
221
 
222
222
  Returns:
223
- mutation_class: Instance of the mutation with output fields populated; `success` is `True` on successful execution and `False` if a handled manager error occurred (after being forwarded to GraphQL._handleGraphQLError).
223
+ mutation_class: Instance of the mutation with output fields populated; `success` is `True` on successful execution and `False` if a handled manager error occurred (after being forwarded to GraphQL._handle_graph_ql_error).
224
224
  """
225
225
  if permission:
226
226
  permission.check(kwargs, info.context.user)
@@ -244,7 +244,7 @@ def graphQlMutation(
244
244
  data["success"] = True
245
245
  return mutation_class(**data)
246
246
  except HANDLED_MANAGER_ERRORS as error:
247
- raise GraphQL._handleGraphQLError(error) from error
247
+ raise GraphQL._handle_graph_ql_error(error) from error
248
248
 
249
249
  # Assemble class dict
250
250
  class_dict: dict[str, Any] = {
@@ -109,9 +109,9 @@ class GraphQLProperty(property):
109
109
 
110
110
 
111
111
  @overload
112
- def graphQlProperty(func: T) -> GraphQLProperty: ...
112
+ def graph_ql_property(func: T) -> GraphQLProperty: ...
113
113
  @overload
114
- def graphQlProperty(
114
+ def graph_ql_property(
115
115
  *,
116
116
  sortable: bool = False,
117
117
  filterable: bool = False,
@@ -119,14 +119,14 @@ def graphQlProperty(
119
119
  ) -> Callable[[T], GraphQLProperty]: ...
120
120
 
121
121
 
122
- def graphQlProperty(
122
+ def graph_ql_property(
123
123
  func: Callable[..., Any] | None = None,
124
124
  *,
125
125
  sortable: bool = False,
126
126
  filterable: bool = False,
127
127
  query_annotation: Any | None = None,
128
128
  ) -> GraphQLProperty | Callable[[T], GraphQLProperty]:
129
- from general_manager.cache.cacheDecorator import cached
129
+ from general_manager.cache.cache_decorator import cached
130
130
 
131
131
  """
132
132
  Decorate a resolver to return a cached ``GraphQLProperty`` descriptor.
general_manager/apps.py CHANGED
@@ -1,22 +1,25 @@
1
1
  from __future__ import annotations
2
- from django.apps import AppConfig
3
- import graphene # type: ignore[import]
4
- import os
5
- from django.conf import settings
6
- from django.urls import path, re_path
7
- from graphene_django.views import GraphQLView # type: ignore[import]
8
- from importlib import import_module, util
2
+
9
3
  import importlib.abc
4
+ import os
10
5
  import sys
11
- from general_manager.manager.generalManager import GeneralManager
12
- from general_manager.manager.meta import GeneralManagerMeta
13
- from general_manager.manager.input import Input
14
- from general_manager.api.property import graphQlProperty
15
- from general_manager.api.graphql import GraphQL
6
+ from importlib import import_module, util
16
7
  from typing import TYPE_CHECKING, Any, Callable, Type, cast
8
+
9
+ import graphene # type: ignore[import]
10
+ from django.apps import AppConfig
11
+ from django.conf import settings
17
12
  from django.core.checks import register
18
- import logging
19
13
  from django.core.management.base import BaseCommand
14
+ from django.urls import path, re_path
15
+ from graphene_django.views import GraphQLView # type: ignore[import]
16
+
17
+ from general_manager.api.graphql import GraphQL
18
+ from general_manager.api.property import graph_ql_property
19
+ from general_manager.logging import get_logger
20
+ from general_manager.manager.general_manager import GeneralManager
21
+ from general_manager.manager.input import Input
22
+ from general_manager.manager.meta import GeneralManagerMeta
20
23
 
21
24
 
22
25
  class MissingRootUrlconfError(RuntimeError):
@@ -43,9 +46,9 @@ class InvalidPermissionClassError(TypeError):
43
46
 
44
47
 
45
48
  if TYPE_CHECKING:
46
- from general_manager.interface.readOnlyInterface import ReadOnlyInterface
49
+ from general_manager.interface.read_only_interface import ReadOnlyInterface
47
50
 
48
- logger = logging.getLogger(__name__)
51
+ logger = get_logger("apps")
49
52
 
50
53
 
51
54
  class GeneralmanagerConfig(AppConfig):
@@ -58,16 +61,16 @@ class GeneralmanagerConfig(AppConfig):
58
61
 
59
62
  Sets up synchronization and schema validation for read-only interfaces, initializes attributes and property accessors for general manager classes, and configures the GraphQL schema and endpoint if enabled in settings.
60
63
  """
61
- self.handleReadOnlyInterface(GeneralManagerMeta.read_only_classes)
62
- self.initializeGeneralManagerClasses(
64
+ self.handle_read_only_interface(GeneralManagerMeta.read_only_classes)
65
+ self.initialize_general_manager_classes(
63
66
  GeneralManagerMeta.pending_attribute_initialization,
64
67
  GeneralManagerMeta.all_classes,
65
68
  )
66
69
  if getattr(settings, "AUTOCREATE_GRAPHQL", False):
67
- self.handleGraphQL(GeneralManagerMeta.pending_graphql_interfaces)
70
+ self.handle_graph_ql(GeneralManagerMeta.pending_graphql_interfaces)
68
71
 
69
72
  @staticmethod
70
- def handleReadOnlyInterface(
73
+ def handle_read_only_interface(
71
74
  read_only_classes: list[Type[GeneralManager]],
72
75
  ) -> None:
73
76
  """
@@ -76,10 +79,13 @@ class GeneralmanagerConfig(AppConfig):
76
79
  Parameters:
77
80
  read_only_classes (list[Type[GeneralManager]]): GeneralManager subclasses whose Interface implements a ReadOnlyInterface; each class will have its read-only data synchronized before management commands and a Django system check registered to verify the Interface schema is up to date.
78
81
  """
79
- GeneralmanagerConfig.patchReadOnlyInterfaceSync(read_only_classes)
80
- from general_manager.interface.readOnlyInterface import ReadOnlyInterface
82
+ GeneralmanagerConfig.patch_read_only_interface_sync(read_only_classes)
83
+ from general_manager.interface.read_only_interface import ReadOnlyInterface
81
84
 
82
- logger.debug("starting to register ReadOnlyInterface schema warnings...")
85
+ logger.debug(
86
+ "registering read-only schema checks",
87
+ context={"count": len(read_only_classes)},
88
+ )
83
89
 
84
90
  def _build_schema_check(
85
91
  manager_cls: Type[GeneralManager], model: Any
@@ -96,7 +102,7 @@ class GeneralmanagerConfig(AppConfig):
96
102
  """
97
103
 
98
104
  def schema_check(*_: Any, **__: Any) -> list[Any]:
99
- return ReadOnlyInterface.ensureSchemaIsUpToDate(manager_cls, model)
105
+ return ReadOnlyInterface.ensure_schema_is_up_to_date(manager_cls, model)
100
106
 
101
107
  return schema_check
102
108
 
@@ -113,18 +119,18 @@ class GeneralmanagerConfig(AppConfig):
113
119
  )
114
120
 
115
121
  @staticmethod
116
- def patchReadOnlyInterfaceSync(
122
+ def patch_read_only_interface_sync(
117
123
  general_manager_classes: list[Type[GeneralManager]],
118
124
  ) -> None:
119
125
  """
120
126
  Ensure the provided GeneralManager classes' ReadOnlyInterfaces synchronize their data before any Django management command is executed.
121
127
 
122
- For each class in `general_manager_classes`, calls the class's `Interface.syncData()` to keep read-only data consistent. Skips synchronization when running the autoreload subprocess of `runserver`.
128
+ For each class in `general_manager_classes`, calls the class's `Interface.sync_data()` to keep read-only data consistent. Skips synchronization when running the autoreload subprocess of `runserver`.
123
129
  Parameters:
124
- general_manager_classes (list[Type[GeneralManager]]): GeneralManager subclasses whose `Interface` implements `syncData`.
130
+ general_manager_classes (list[Type[GeneralManager]]): GeneralManager subclasses whose `Interface` implements `sync_data`.
125
131
  """
126
132
  """
127
- Wrap BaseCommand.run_from_argv to call `syncData()` on registered ReadOnlyInterfaces before executing the original command.
133
+ Wrap BaseCommand.run_from_argv to call `sync_data()` on registered ReadOnlyInterfaces before executing the original command.
128
134
 
129
135
  Skips synchronization when the command is `runserver` and the process is the autoreload subprocess.
130
136
  Parameters:
@@ -133,7 +139,7 @@ class GeneralmanagerConfig(AppConfig):
133
139
  Returns:
134
140
  The result returned by the original `BaseCommand.run_from_argv` call.
135
141
  """
136
- from general_manager.interface.readOnlyInterface import ReadOnlyInterface
142
+ from general_manager.interface.read_only_interface import ReadOnlyInterface
137
143
 
138
144
  original_run_from_argv = BaseCommand.run_from_argv
139
145
 
@@ -141,7 +147,7 @@ class GeneralmanagerConfig(AppConfig):
141
147
  self: BaseCommand,
142
148
  argv: list[str],
143
149
  ) -> None:
144
- # Ensure syncData is only called at real run of runserver
150
+ # Ensure sync_data is only called at real run of runserver
145
151
  """
146
152
  Synchronizes all registered ReadOnlyInterface data before running a Django management command, except when running the autoreload subprocess of `runserver`.
147
153
 
@@ -154,14 +160,27 @@ class GeneralmanagerConfig(AppConfig):
154
160
  run_main = os.environ.get("RUN_MAIN") == "true"
155
161
  command = argv[1] if len(argv) > 1 else None
156
162
  if command != "runserver" or run_main:
157
- logger.debug("start syncing ReadOnlyInterface data...")
163
+ logger.debug(
164
+ "syncing read-only interfaces",
165
+ context={
166
+ "command": command,
167
+ "autoreload": not run_main if command == "runserver" else False,
168
+ "count": len(general_manager_classes),
169
+ },
170
+ )
158
171
  for general_manager_class in general_manager_classes:
159
172
  read_only_interface = cast(
160
173
  Type[ReadOnlyInterface], general_manager_class.Interface
161
174
  )
162
- read_only_interface.syncData()
163
-
164
- logger.debug("finished syncing ReadOnlyInterface data.")
175
+ read_only_interface.sync_data()
176
+
177
+ logger.debug(
178
+ "finished syncing read-only interfaces",
179
+ context={
180
+ "command": command,
181
+ "count": len(general_manager_classes),
182
+ },
183
+ )
165
184
 
166
185
  result = original_run_from_argv(self, argv)
167
186
  return result
@@ -169,20 +188,26 @@ class GeneralmanagerConfig(AppConfig):
169
188
  BaseCommand.run_from_argv = run_from_argv_with_sync # type: ignore[assignment]
170
189
 
171
190
  @staticmethod
172
- def initializeGeneralManagerClasses(
191
+ def initialize_general_manager_classes(
173
192
  pending_attribute_initialization: list[Type[GeneralManager]],
174
193
  all_classes: list[Type[GeneralManager]],
175
194
  ) -> None:
176
195
  """
177
196
  Initialize GeneralManager classes' interface attributes, create attribute-based accessors, wire GraphQL connection properties between related managers, and validate each class's permission configuration.
178
197
 
179
- For each class in `pending_attribute_initialization` this assigns the class's Interface attributes to its internal `_attributes` and creates property accessors for those attributes. For each class in `all_classes` this scans its Interface `input_fields` for inputs whose type is another GeneralManager subclass and adds a GraphQL property on the connected manager that resolves related objects filtered by the input attribute. Finally, validate and normalize the Permission attribute on every class via GeneralmanagerConfig.checkPermissionClass.
198
+ For each class in `pending_attribute_initialization` this assigns the class's Interface attributes to its internal `_attributes` and creates property accessors for those attributes. For each class in `all_classes` this scans its Interface `input_fields` for inputs whose type is another GeneralManager subclass and adds a GraphQL property on the connected manager that resolves related objects filtered by the input attribute. Finally, validate and normalize the Permission attribute on every class via GeneralmanagerConfig.check_permission_class.
180
199
 
181
200
  Parameters:
182
201
  pending_attribute_initialization (list[type[GeneralManager]]): GeneralManager classes whose Interface attributes need to be initialized and whose attribute properties should be created.
183
202
  all_classes (list[type[GeneralManager]]): All registered GeneralManager classes to inspect for input-field connections and to validate permissions.
184
203
  """
185
- logger.debug("Initializing GeneralManager classes...")
204
+ logger.debug(
205
+ "initializing general manager classes",
206
+ context={
207
+ "pending_attributes": len(pending_attribute_initialization),
208
+ "total": len(all_classes),
209
+ },
210
+ )
186
211
 
187
212
  def _build_connection_resolver(
188
213
  attribute_key: str, manager_cls: Type[GeneralManager]
@@ -204,15 +229,21 @@ class GeneralmanagerConfig(AppConfig):
204
229
  resolver.__annotations__ = {"return": manager_cls}
205
230
  return resolver
206
231
 
207
- logger.debug("starting to create attributes for GeneralManager classes...")
232
+ logger.debug(
233
+ "creating manager attributes",
234
+ context={"pending_attributes": len(pending_attribute_initialization)},
235
+ )
208
236
  for general_manager_class in pending_attribute_initialization:
209
- attributes = general_manager_class.Interface.getAttributes()
237
+ attributes = general_manager_class.Interface.get_attributes()
210
238
  general_manager_class._attributes = attributes
211
- GeneralManagerMeta.createAtPropertiesForAttributes(
239
+ GeneralManagerMeta.create_at_properties_for_attributes(
212
240
  attributes.keys(), general_manager_class
213
241
  )
214
242
 
215
- logger.debug("starting to connect inputs to other general manager classes...")
243
+ logger.debug(
244
+ "linking manager inputs",
245
+ context={"total_classes": len(all_classes)},
246
+ )
216
247
  for general_manager_class in all_classes:
217
248
  attributes = getattr(general_manager_class.Interface, "input_fields", {})
218
249
  for attribute_name, attribute in attributes.items():
@@ -226,13 +257,13 @@ class GeneralmanagerConfig(AppConfig):
226
257
  setattr(
227
258
  connected_manager,
228
259
  f"{general_manager_class.__name__.lower()}_list",
229
- graphQlProperty(resolver),
260
+ graph_ql_property(resolver),
230
261
  )
231
262
  for general_manager_class in all_classes:
232
- GeneralmanagerConfig.checkPermissionClass(general_manager_class)
263
+ GeneralmanagerConfig.check_permission_class(general_manager_class)
233
264
 
234
265
  @staticmethod
235
- def handleGraphQL(
266
+ def handle_graph_ql(
236
267
  pending_graphql_interfaces: list[Type[GeneralManager]],
237
268
  ) -> None:
238
269
  """
@@ -241,10 +272,13 @@ class GeneralmanagerConfig(AppConfig):
241
272
  Parameters:
242
273
  pending_graphql_interfaces (list[Type[GeneralManager]]): GeneralManager classes for which GraphQL interfaces, mutations, and optional subscriptions should be created and included in the assembled schema.
243
274
  """
244
- logger.debug("Starting to create GraphQL interfaces and mutations...")
275
+ logger.debug(
276
+ "creating graphql interfaces and mutations",
277
+ context={"pending": len(GeneralManagerMeta.pending_graphql_interfaces)},
278
+ )
245
279
  for general_manager_class in pending_graphql_interfaces:
246
- GraphQL.createGraphqlInterface(general_manager_class)
247
- GraphQL.createGraphqlMutation(general_manager_class)
280
+ GraphQL.create_graphql_interface(general_manager_class)
281
+ GraphQL.create_graphql_mutation(general_manager_class)
248
282
 
249
283
  query_class = type("Query", (graphene.ObjectType,), GraphQL._query_fields)
250
284
  GraphQL._query_class = query_class
@@ -279,10 +313,10 @@ class GeneralmanagerConfig(AppConfig):
279
313
  schema_kwargs["subscription"] = GraphQL._subscription_class
280
314
  schema = graphene.Schema(**schema_kwargs)
281
315
  GraphQL._schema = schema
282
- GeneralmanagerConfig.addGraphqlUrl(schema)
316
+ GeneralmanagerConfig.add_graphql_url(schema)
283
317
 
284
318
  @staticmethod
285
- def addGraphqlUrl(schema: graphene.Schema) -> None:
319
+ def add_graphql_url(schema: graphene.Schema) -> None:
286
320
  """
287
321
  Add a GraphQL endpoint to the project's URL configuration and ensure the ASGI subscription route is configured.
288
322
 
@@ -292,7 +326,13 @@ class GeneralmanagerConfig(AppConfig):
292
326
  Raises:
293
327
  MissingRootUrlconfError: If ROOT_URLCONF is not defined in Django settings.
294
328
  """
295
- logging.debug("Adding GraphQL URL to Django settings...")
329
+ logger.debug(
330
+ "configuring graphql http endpoint",
331
+ context={
332
+ "root_urlconf": getattr(settings, "ROOT_URLCONF", None),
333
+ "graphql_url": getattr(settings, "GRAPHQL_URL", "graphql"),
334
+ },
335
+ )
296
336
  root_url_conf_path = getattr(settings, "ROOT_URLCONF", None)
297
337
  graph_ql_url = getattr(settings, "GRAPHQL_URL", "graphql")
298
338
  if not root_url_conf_path:
@@ -317,15 +357,18 @@ class GeneralmanagerConfig(AppConfig):
317
357
  """
318
358
  asgi_path = getattr(settings, "ASGI_APPLICATION", None)
319
359
  if not asgi_path:
320
- logger.debug("ASGI_APPLICATION not configured; skipping websocket setup.")
360
+ logger.debug(
361
+ "asgi application missing",
362
+ context={"graphql_url": graphql_url},
363
+ )
321
364
  return
322
365
 
323
366
  try:
324
367
  module_path, attr_name = asgi_path.rsplit(".", 1)
325
368
  except ValueError:
326
369
  logger.warning(
327
- "ASGI_APPLICATION '%s' is not a valid module path; skipping websocket setup.",
328
- asgi_path,
370
+ "invalid asgi application path",
371
+ context={"asgi_application": asgi_path},
329
372
  )
330
373
  return
331
374
 
@@ -334,9 +377,12 @@ class GeneralmanagerConfig(AppConfig):
334
377
  except RuntimeError as exc:
335
378
  if "populate() isn't reentrant" not in str(exc):
336
379
  logger.warning(
337
- "Unable to import ASGI module '%s': %s",
338
- module_path,
339
- exc,
380
+ "unable to import asgi module",
381
+ context={
382
+ "module": module_path,
383
+ "error": type(exc).__name__,
384
+ "message": str(exc),
385
+ },
340
386
  exc_info=True,
341
387
  )
342
388
  return
@@ -344,8 +390,8 @@ class GeneralmanagerConfig(AppConfig):
344
390
  spec = util.find_spec(module_path)
345
391
  if spec is None or spec.loader is None:
346
392
  logger.warning(
347
- "Could not locate loader for ASGI module '%s'; skipping websocket setup.",
348
- module_path,
393
+ "missing loader for asgi module",
394
+ context={"module": module_path},
349
395
  )
350
396
  return
351
397
 
@@ -416,7 +462,13 @@ class GeneralmanagerConfig(AppConfig):
416
462
  return
417
463
  except ImportError as exc: # pragma: no cover - defensive
418
464
  logger.warning(
419
- "Unable to import ASGI module '%s': %s", module_path, exc, exc_info=True
465
+ "unable to import asgi module",
466
+ context={
467
+ "module": module_path,
468
+ "error": type(exc).__name__,
469
+ "message": str(exc),
470
+ },
471
+ exc_info=True,
420
472
  )
421
473
  return
422
474
 
@@ -447,8 +499,11 @@ class GeneralmanagerConfig(AppConfig):
447
499
  RuntimeError,
448
500
  ) as exc: # pragma: no cover - optional dependency
449
501
  logger.debug(
450
- "Channels or GraphQL subscription consumer unavailable (%s); skipping websocket setup.",
451
- exc,
502
+ "channels dependencies unavailable",
503
+ context={
504
+ "error": type(exc).__name__,
505
+ "message": str(exc),
506
+ },
452
507
  )
453
508
  return
454
509
 
@@ -459,8 +514,8 @@ class GeneralmanagerConfig(AppConfig):
459
514
 
460
515
  if not hasattr(websocket_patterns, "append"):
461
516
  logger.warning(
462
- "websocket_urlpatterns in '%s' does not support appending; skipping websocket setup.",
463
- asgi_module.__name__,
517
+ "websocket_urlpatterns not appendable",
518
+ context={"module": asgi_module.__name__},
464
519
  )
465
520
  return
466
521
 
@@ -498,7 +553,7 @@ class GeneralmanagerConfig(AppConfig):
498
553
  setattr(asgi_module, attr_name, wrapped_application)
499
554
 
500
555
  @staticmethod
501
- def checkPermissionClass(general_manager_class: Type[GeneralManager]) -> None:
556
+ def check_permission_class(general_manager_class: Type[GeneralManager]) -> None:
502
557
  """
503
558
  Validate and normalize a GeneralManager class's Permission attribute.
504
559
 
@@ -510,8 +565,8 @@ class GeneralmanagerConfig(AppConfig):
510
565
  Raises:
511
566
  InvalidPermissionClassError: If the existing Permission attribute is not a subclass of BasePermission.
512
567
  """
513
- from general_manager.permission.basePermission import BasePermission
514
- from general_manager.permission.managerBasedPermission import (
568
+ from general_manager.permission.base_permission import BasePermission
569
+ from general_manager.permission.manager_based_permission import (
515
570
  ManagerBasedPermission,
516
571
  )
517
572
 
@@ -14,10 +14,10 @@ from typing import (
14
14
  GeneralManagerType = TypeVar("GeneralManagerType", bound="GeneralManager")
15
15
 
16
16
  if TYPE_CHECKING:
17
- from general_manager.manager.generalManager import GeneralManager
18
- from general_manager.manager.groupManager import GroupManager
19
- from general_manager.bucket.groupBucket import GroupBucket
20
- from general_manager.interface.baseInterface import InterfaceBase
17
+ from general_manager.manager.general_manager import GeneralManager
18
+ from general_manager.manager.group_manager import GroupManager
19
+ from general_manager.bucket.group_bucket import GroupBucket
20
+ from general_manager.interface.base_interface import InterfaceBase
21
21
 
22
22
 
23
23
  class Bucket(ABC, Generic[GeneralManagerType]):
@@ -243,7 +243,7 @@ class Bucket(ABC, Generic[GeneralManagerType]):
243
243
  Returns:
244
244
  GroupBucket[GeneralManagerType]: Bucket grouping items by the provided keys.
245
245
  """
246
- from general_manager.bucket.groupBucket import GroupBucket
246
+ from general_manager.bucket.group_bucket import GroupBucket
247
247
 
248
248
  return GroupBucket(self._manager_class, group_by_keys, self)
249
249
 
@@ -17,13 +17,13 @@ from typing import (
17
17
  )
18
18
  from operator import attrgetter
19
19
  from copy import deepcopy
20
- from general_manager.interface.baseInterface import (
20
+ from general_manager.interface.base_interface import (
21
21
  generalManagerClassName,
22
22
  GeneralManagerType,
23
23
  )
24
- from general_manager.bucket.baseBucket import Bucket
24
+ from general_manager.bucket.base_bucket import Bucket
25
25
  from general_manager.manager.input import Input
26
- from general_manager.utils.filterParser import parse_filters
26
+ from general_manager.utils.filter_parser import parse_filters
27
27
 
28
28
  if TYPE_CHECKING:
29
29
  from general_manager.api.property import GraphQLProperty
@@ -164,7 +164,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
164
164
  Raises:
165
165
  InvalidCalculationInterfaceError: If the manager_class.Interface does not inherit from CalculationInterface.
166
166
  """
167
- from general_manager.interface.calculationInterface import (
167
+ from general_manager.interface.calculation_interface import (
168
168
  CalculationInterface,
169
169
  )
170
170
 
@@ -181,8 +181,8 @@ class CalculationBucket(Bucket[GeneralManagerType]):
181
181
  {} if exclude_definitions is None else exclude_definitions
182
182
  )
183
183
 
184
- properties = self._manager_class.Interface.getGraphQLProperties()
185
- possible_values = self.transformPropertiesToInputFields(
184
+ properties = self._manager_class.Interface.get_graph_ql_properties()
185
+ possible_values = self.transform_properties_to_input_fields(
186
186
  properties, self.input_fields
187
187
  )
188
188
 
@@ -259,7 +259,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
259
259
  IncompatibleBucketTypeError: If `other` is neither a CalculationBucket nor a compatible manager instance.
260
260
  IncompatibleBucketManagerError: If `other` is a CalculationBucket for a different manager class.
261
261
  """
262
- from general_manager.manager.generalManager import GeneralManager
262
+ from general_manager.manager.general_manager import GeneralManager
263
263
 
264
264
  if isinstance(other, GeneralManager) and other.__class__ == self._manager_class:
265
265
  return self.__or__(self.filter(id__in=[other.identification]))
@@ -322,7 +322,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
322
322
  return f"{self.__class__.__name__}({self._manager_class.__name__}, {self.filter_definitions}, {self.exclude_definitions}, {self.sort_key}, {self.reverse})"
323
323
 
324
324
  @staticmethod
325
- def transformPropertiesToInputFields(
325
+ def transform_properties_to_input_fields(
326
326
  properties: dict[str, GraphQLProperty], input_fields: dict[str, Input]
327
327
  ) -> dict[str, Input]:
328
328
  """
@@ -420,7 +420,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
420
420
  for combo in combinations:
421
421
  yield self._manager_class(**combo)
422
422
 
423
- def _sortFilters(self, sorted_inputs: List[str]) -> SortedFilters:
423
+ def _sort_filters(self, sorted_inputs: List[str]) -> SortedFilters:
424
424
  """
425
425
  Partition filters into input- and property-based buckets.
426
426
 
@@ -467,7 +467,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
467
467
 
468
468
  if self._data is None:
469
469
  sorted_inputs = self.topological_sort_inputs()
470
- sorted_filters = self._sortFilters(sorted_inputs)
470
+ sorted_filters = self._sort_filters(sorted_inputs)
471
471
  current_combinations = self._generate_input_combinations(
472
472
  sorted_inputs,
473
473
  sorted_filters["input_filters"],