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
@@ -3,15 +3,19 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from django.conf import settings
6
- from typing import Any, Type, TYPE_CHECKING, ClassVar, TypeVar, Iterable, cast
7
- from general_manager.interface.baseInterface import InterfaceBase
6
+ from typing import TYPE_CHECKING, Any, ClassVar, Iterable, Type, TypeVar, cast
7
+
8
+ from general_manager.interface.base_interface import InterfaceBase
9
+ from general_manager.logging import get_logger
8
10
 
9
11
  if TYPE_CHECKING:
10
- from general_manager.manager.generalManager import GeneralManager
12
+ from general_manager.manager.general_manager import GeneralManager
11
13
 
12
14
 
13
15
  GeneralManagerType = TypeVar("GeneralManagerType", bound="GeneralManager")
14
16
 
17
+ logger = get_logger("manager.meta")
18
+
15
19
 
16
20
  class InvalidInterfaceTypeError(TypeError):
17
21
  """Raised when a GeneralManager is configured with an incompatible Interface class."""
@@ -78,7 +82,7 @@ class GeneralManagerMeta(type):
78
82
  """
79
83
  Create a GeneralManager subclass, integrate any declared Interface hooks, and register the class for pending initialization and GraphQL processing.
80
84
 
81
- If the class body defines an `Interface`, validates it is a subclass of `InterfaceBase`, invokes the interface's `handleInterface()` pre-creation hook to allow modification of the class namespace, creates the class, then invokes the post-creation hook and registers the class for attribute initialization and global tracking. If `Interface` is not defined, creates the class directly. If `settings.AUTOCREATE_GRAPHQL` is true, registers the created class for GraphQL interface processing.
85
+ If the class body defines an `Interface`, validates it is a subclass of `InterfaceBase`, invokes the interface's `handle_interface()` pre-creation hook to allow modification of the class namespace, creates the class, then invokes the post-creation hook and registers the class for attribute initialization and global tracking. If `Interface` is not defined, creates the class directly. If `settings.AUTOCREATE_GRAPHQL` is true, registers the created class for GraphQL interface processing.
82
86
 
83
87
  Parameters:
84
88
  mcs (type): The metaclass creating the class.
@@ -89,8 +93,16 @@ class GeneralManagerMeta(type):
89
93
  Returns:
90
94
  type: The newly created subclass, possibly modified by Interface hooks.
91
95
  """
92
-
93
- def createNewGeneralManagerClass(
96
+ logger.debug(
97
+ "creating manager class",
98
+ context={
99
+ "class_name": name,
100
+ "module": attrs.get("__module__"),
101
+ "has_interface": "Interface" in attrs,
102
+ },
103
+ )
104
+
105
+ def create_new_general_manager_class(
94
106
  mcs: type["GeneralManagerMeta"],
95
107
  name: str,
96
108
  bases: tuple[type, ...],
@@ -103,23 +115,42 @@ class GeneralManagerMeta(type):
103
115
  interface = attrs.pop("Interface")
104
116
  if not issubclass(interface, InterfaceBase):
105
117
  raise InvalidInterfaceTypeError(interface.__name__)
106
- preCreation, postCreation = interface.handleInterface()
107
- attrs, interface_cls, model = preCreation(name, attrs, interface)
108
- new_class = createNewGeneralManagerClass(mcs, name, bases, attrs)
109
- postCreation(new_class, interface_cls, model)
118
+ pre_creation, post_creation = interface.handle_interface()
119
+ attrs, interface_cls, model = pre_creation(name, attrs, interface)
120
+ new_class = create_new_general_manager_class(mcs, name, bases, attrs)
121
+ post_creation(new_class, interface_cls, model)
110
122
  mcs.pending_attribute_initialization.append(new_class)
111
123
  mcs.all_classes.append(new_class)
124
+ logger.debug(
125
+ "registered manager class with interface",
126
+ context={
127
+ "class_name": new_class.__name__,
128
+ "interface": interface_cls.__name__,
129
+ },
130
+ )
112
131
 
113
132
  else:
114
- new_class = createNewGeneralManagerClass(mcs, name, bases, attrs)
133
+ new_class = create_new_general_manager_class(mcs, name, bases, attrs)
134
+ logger.debug(
135
+ "registered manager class without interface",
136
+ context={
137
+ "class_name": new_class.__name__,
138
+ },
139
+ )
115
140
 
116
141
  if getattr(settings, "AUTOCREATE_GRAPHQL", False):
117
142
  mcs.pending_graphql_interfaces.append(new_class)
143
+ logger.debug(
144
+ "queued manager for graphql generation",
145
+ context={
146
+ "class_name": new_class.__name__,
147
+ },
148
+ )
118
149
 
119
150
  return new_class
120
151
 
121
152
  @staticmethod
122
- def createAtPropertiesForAttributes(
153
+ def create_at_properties_for_attributes(
123
154
  attributes: Iterable[str], new_class: Type[GeneralManager]
124
155
  ) -> None:
125
156
  """
@@ -132,14 +163,14 @@ class GeneralManagerMeta(type):
132
163
  new_class (Type[GeneralManager]): Class that will receive the generated descriptor attributes.
133
164
  """
134
165
 
135
- def descriptorMethod(
166
+ def descriptor_method(
136
167
  attr_name: str,
137
168
  new_class: type,
138
169
  ) -> object:
139
170
  """
140
171
  Create a descriptor that provides attribute access backed by an instance's interface attributes.
141
172
 
142
- When accessed on the class, the descriptor returns the field type by delegating to the class's `Interface.getFieldType` for the configured attribute name. When accessed on an instance, it returns the value stored in `instance._attributes[attr_name]`. If the stored value is callable, it is invoked with `instance._interface` and the resulting value is returned. If the attribute is not present on the instance, a `MissingAttributeError` is raised. If invoking a callable attribute raises an exception, that error is wrapped in `AttributeEvaluationError`.
173
+ When accessed on the class, the descriptor returns the field type by delegating to the class's `Interface.get_field_type` for the configured attribute name. When accessed on an instance, it returns the value stored in `instance._attributes[attr_name]`. If the stored value is callable, it is invoked with `instance._interface` and the resulting value is returned. If the attribute is not present on the instance, a `MissingAttributeError` is raised. If invoking a callable attribute raises an exception, that error is wrapped in `AttributeEvaluationError`.
143
174
 
144
175
  Parameters:
145
176
  attr_name (str): The name of the attribute the descriptor resolves.
@@ -164,7 +195,7 @@ class GeneralManagerMeta(type):
164
195
  """
165
196
  Provide the class field type when accessed on the class, or resolve and return the stored attribute value for an instance.
166
197
 
167
- When accessed on a class, returns the field type from the class's Interface via Interface.getFieldType.
198
+ When accessed on a class, returns the field type from the class's Interface via Interface.get_field_type.
168
199
  When accessed on an instance, retrieves the value stored in instance._attributes for this descriptor's attribute name;
169
200
  if the stored value is callable, it is invoked with instance._interface and the result is returned.
170
201
 
@@ -176,9 +207,16 @@ class GeneralManagerMeta(type):
176
207
  AttributeEvaluationError: If calling a callable attribute raises an exception; the original exception is wrapped.
177
208
  """
178
209
  if instance is None:
179
- return self._class.Interface.getFieldType(self._attr_name)
210
+ return self._class.Interface.get_field_type(self._attr_name)
180
211
  attribute = instance._attributes.get(self._attr_name, _nonExistent)
181
212
  if attribute is _nonExistent:
213
+ logger.warning(
214
+ "missing attribute on manager instance",
215
+ context={
216
+ "attribute": self._attr_name,
217
+ "manager": instance.__class__.__name__,
218
+ },
219
+ )
182
220
  raise MissingAttributeError(
183
221
  self._attr_name, instance.__class__.__name__
184
222
  )
@@ -186,10 +224,18 @@ class GeneralManagerMeta(type):
186
224
  try:
187
225
  attribute = attribute(instance._interface)
188
226
  except Exception as e:
227
+ logger.exception(
228
+ "attribute evaluation failed",
229
+ context={
230
+ "attribute": self._attr_name,
231
+ "manager": instance.__class__.__name__,
232
+ "error": type(e).__name__,
233
+ },
234
+ )
189
235
  raise AttributeEvaluationError(self._attr_name, e) from e
190
236
  return attribute
191
237
 
192
238
  return Descriptor(attr_name, cast(Type[Any], new_class))
193
239
 
194
240
  for attr_name in attributes:
195
- setattr(new_class, attr_name, descriptorMethod(attr_name, new_class))
241
+ setattr(new_class, attr_name, descriptor_method(attr_name, new_class))
@@ -194,7 +194,7 @@ class Measurement:
194
194
  raise InvalidMeasurementInitializationError() from error
195
195
  if not isinstance(value, Decimal):
196
196
  value = Decimal(str(value))
197
- self.__quantity = ureg.Quantity(self.formatDecimal(value), unit)
197
+ self.__quantity = ureg.Quantity(self.format_decimal(value), unit)
198
198
 
199
199
  def __getstate__(self) -> dict[str, str]:
200
200
  """
@@ -221,7 +221,7 @@ class Measurement:
221
221
  """
222
222
  value = Decimal(state["magnitude"])
223
223
  unit = state["unit"]
224
- self.__quantity = ureg.Quantity(self.formatDecimal(value), unit)
224
+ self.__quantity = ureg.Quantity(self.format_decimal(value), unit)
225
225
 
226
226
  @property
227
227
  def quantity(self) -> PlainQuantity:
@@ -282,7 +282,7 @@ class Measurement:
282
282
  return cls(value, unit)
283
283
 
284
284
  @staticmethod
285
- def formatDecimal(value: Decimal) -> Decimal:
285
+ def format_decimal(value: Decimal) -> Decimal:
286
286
  """
287
287
  Normalise decimals so integers have no fractional component.
288
288
 
@@ -1,23 +1,25 @@
1
1
  """Base permission contract used by GeneralManager instances."""
2
2
 
3
3
  from __future__ import annotations
4
+
4
5
  from abc import ABC, abstractmethod
5
6
  from typing import TYPE_CHECKING, Any, Literal, TypeAlias, cast
6
- from general_manager.permission.permissionChecks import permission_functions
7
7
 
8
- from django.contrib.auth.models import AnonymousUser, AbstractBaseUser, AbstractUser
9
- from general_manager.permission.permissionDataManager import PermissionDataManager
8
+ from django.contrib.auth.models import AbstractBaseUser, AbstractUser, AnonymousUser
9
+
10
+ from general_manager.logging import get_logger
11
+ from general_manager.permission.permission_checks import permission_functions
12
+ from general_manager.permission.permission_data_manager import PermissionDataManager
10
13
  from general_manager.permission.utils import (
11
- validatePermissionString,
12
14
  PermissionNotFoundError,
15
+ validate_permission_string,
13
16
  )
14
- import logging
15
17
 
16
18
  if TYPE_CHECKING:
17
- from general_manager.manager.generalManager import GeneralManager
19
+ from general_manager.manager.general_manager import GeneralManager
18
20
  from general_manager.manager.meta import GeneralManagerMeta
19
21
 
20
- logger = logging.getLogger(__name__)
22
+ logger = get_logger("permission.base")
21
23
 
22
24
  UserLike: TypeAlias = AbstractBaseUser | AnonymousUser
23
25
 
@@ -63,7 +65,7 @@ class BasePermission(ABC):
63
65
  return self._request_user
64
66
 
65
67
  @classmethod
66
- def checkCreatePermission(
68
+ def check_create_permission(
67
69
  cls,
68
70
  data: dict[str, Any],
69
71
  manager: type[GeneralManager],
@@ -82,22 +84,29 @@ class BasePermission(ABC):
82
84
  Raises:
83
85
  PermissionCheckError: If one or more attributes in `data` are denied for the resolved `request_user`.
84
86
  """
85
- request_user = cls.getUserWithId(request_user)
87
+ request_user = cls.get_user_with_id(request_user)
86
88
  errors = []
87
89
  permission_data = PermissionDataManager(permission_data=data, manager=manager)
88
90
  Permission = cls(permission_data, request_user)
91
+ user_identifier = getattr(request_user, "id", None)
89
92
  for key in data.keys():
90
- is_allowed = Permission.checkPermission("create", key)
93
+ is_allowed = Permission.check_permission("create", key)
91
94
  if not is_allowed:
92
- logger.debug(
93
- f"Permission denied for {key} with value {data[key]} for user {request_user}"
95
+ logger.info(
96
+ "permission denied",
97
+ context={
98
+ "manager": manager.__name__,
99
+ "action": "create",
100
+ "attribute": key,
101
+ "user_id": user_identifier,
102
+ },
94
103
  )
95
104
  errors.append(f"Create permission denied for attribute '{key}'")
96
105
  if errors:
97
106
  raise PermissionCheckError(request_user, errors)
98
107
 
99
108
  @classmethod
100
- def checkUpdatePermission(
109
+ def check_update_permission(
101
110
  cls,
102
111
  data: dict[str, Any],
103
112
  old_manager_instance: GeneralManager,
@@ -109,30 +118,37 @@ class BasePermission(ABC):
109
118
  Parameters:
110
119
  data (dict[str, Any]): Mapping of attribute names to new values to be applied.
111
120
  old_manager_instance (GeneralManager): Existing manager instance whose current state is used to evaluate update permissions.
112
- request_user (UserLike | Any): User instance or user id; non-user values will be resolved to a User or AnonymousUser via getUserWithId.
121
+ request_user (UserLike | Any): User instance or user id; non-user values will be resolved to a User or AnonymousUser via get_user_with_id.
113
122
 
114
123
  Raises:
115
124
  PermissionCheckError: Raised with a list of error messages when one or more fields are not permitted to be updated.
116
125
  """
117
- request_user = cls.getUserWithId(request_user)
126
+ request_user = cls.get_user_with_id(request_user)
118
127
 
119
128
  errors = []
120
- permission_data = PermissionDataManager.forUpdate(
129
+ permission_data = PermissionDataManager.for_update(
121
130
  base_data=old_manager_instance, update_data=data
122
131
  )
123
132
  Permission = cls(permission_data, request_user)
133
+ user_identifier = getattr(request_user, "id", None)
124
134
  for key in data.keys():
125
- is_allowed = Permission.checkPermission("update", key)
135
+ is_allowed = Permission.check_permission("update", key)
126
136
  if not is_allowed:
127
- logger.debug(
128
- f"Permission denied for {key} with value {data[key]} for user {request_user}"
137
+ logger.info(
138
+ "permission denied",
139
+ context={
140
+ "manager": old_manager_instance.__class__.__name__,
141
+ "action": "update",
142
+ "attribute": key,
143
+ "user_id": user_identifier,
144
+ },
129
145
  )
130
146
  errors.append(f"Update permission denied for attribute '{key}'")
131
147
  if errors:
132
148
  raise PermissionCheckError(request_user, errors)
133
149
 
134
150
  @classmethod
135
- def checkDeletePermission(
151
+ def check_delete_permission(
136
152
  cls,
137
153
  manager_instance: GeneralManager,
138
154
  request_user: UserLike | Any,
@@ -149,23 +165,30 @@ class BasePermission(ABC):
149
165
  Raises:
150
166
  PermissionCheckError: If one or more attributes are not permitted for deletion by request_user. The exception carries the user and the list of denial messages.
151
167
  """
152
- request_user = cls.getUserWithId(request_user)
168
+ request_user = cls.get_user_with_id(request_user)
153
169
 
154
170
  errors = []
155
171
  permission_data = PermissionDataManager(manager_instance)
156
172
  Permission = cls(permission_data, request_user)
173
+ user_identifier = getattr(request_user, "id", None)
157
174
  for key in manager_instance.__dict__.keys():
158
- is_allowed = Permission.checkPermission("delete", key)
175
+ is_allowed = Permission.check_permission("delete", key)
159
176
  if not is_allowed:
160
- logger.debug(
161
- f"Permission denied for {key} with value {getattr(manager_instance, key)} for user {request_user}"
177
+ logger.info(
178
+ "permission denied",
179
+ context={
180
+ "manager": manager_instance.__class__.__name__,
181
+ "action": "delete",
182
+ "attribute": key,
183
+ "user_id": user_identifier,
184
+ },
162
185
  )
163
186
  errors.append(f"Delete permission denied for attribute '{key}'")
164
187
  if errors:
165
188
  raise PermissionCheckError(request_user, errors)
166
189
 
167
190
  @staticmethod
168
- def getUserWithId(
191
+ def get_user_with_id(
169
192
  user: Any | UserLike,
170
193
  ) -> UserLike:
171
194
  """
@@ -185,12 +208,12 @@ class BasePermission(ABC):
185
208
  if isinstance(user, (AbstractBaseUser, AnonymousUser)):
186
209
  return user
187
210
  try:
188
- return User.objects.get(id=user)
189
- except User.DoesNotExist:
211
+ return User.objects.get(pk=user)
212
+ except (User.DoesNotExist, ValueError, TypeError):
190
213
  return AnonymousUser()
191
214
 
192
215
  @abstractmethod
193
- def checkPermission(
216
+ def check_permission(
194
217
  self,
195
218
  action: Literal["create", "read", "update", "delete"],
196
219
  attribute: str,
@@ -207,13 +230,13 @@ class BasePermission(ABC):
207
230
  """
208
231
  raise NotImplementedError
209
232
 
210
- def getPermissionFilter(
233
+ def get_permission_filter(
211
234
  self,
212
235
  ) -> list[dict[Literal["filter", "exclude"], dict[str, str]]]:
213
236
  """Return the filter/exclude constraints associated with this permission."""
214
237
  raise NotImplementedError
215
238
 
216
- def _getPermissionFilter(
239
+ def _get_permission_filter(
217
240
  self, permission: str
218
241
  ) -> dict[Literal["filter", "exclude"], dict[str, str]]:
219
242
  """
@@ -241,7 +264,7 @@ class BasePermission(ABC):
241
264
  return {"filter": {}, "exclude": {}}
242
265
  return permission_filter
243
266
 
244
- def validatePermissionString(
267
+ def validate_permission_string(
245
268
  self,
246
269
  permission: str,
247
270
  ) -> bool:
@@ -254,7 +277,7 @@ class BasePermission(ABC):
254
277
  Returns:
255
278
  bool: True when every sub-permission evaluates to True for the current user.
256
279
  """
257
- return validatePermissionString(
280
+ return validate_permission_string(
258
281
  permission,
259
282
  self.instance,
260
283
  cast(AbstractUser | AnonymousUser, self.request_user),
@@ -2,13 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
  from typing import TYPE_CHECKING, Literal, Optional, Dict
5
- from general_manager.permission.basePermission import BasePermission
5
+ from general_manager.permission.base_permission import BasePermission
6
6
 
7
7
  if TYPE_CHECKING:
8
- from general_manager.permission.permissionDataManager import (
8
+ from general_manager.permission.permission_data_manager import (
9
9
  PermissionDataManager,
10
10
  )
11
- from general_manager.manager.generalManager import GeneralManager
11
+ from general_manager.manager.general_manager import GeneralManager
12
12
  from django.contrib.auth.models import AbstractUser
13
13
 
14
14
  type permission_type = Literal[
@@ -86,10 +86,10 @@ class ManagerBasedPermission(BasePermission):
86
86
  request_user (AbstractUser): User whose permissions are being checked.
87
87
  """
88
88
  super().__init__(instance, request_user)
89
- self.__setPermissions()
89
+ self.__set_permissions()
90
90
 
91
- self.__attribute_permissions = self.__getAttributePermissions()
92
- self.__based_on_permission = self.__getBasedOnPermission()
91
+ self.__attribute_permissions = self.__get_attribute_permissions()
92
+ self.__based_on_permission = self.__get_based_on_permission()
93
93
  self.__overall_results: Dict[permission_type, Optional[bool]] = {
94
94
  "create": None,
95
95
  "read": None,
@@ -97,7 +97,7 @@ class ManagerBasedPermission(BasePermission):
97
97
  "delete": None,
98
98
  }
99
99
 
100
- def __setPermissions(self, skip_based_on: bool = False) -> None:
100
+ def __set_permissions(self, skip_based_on: bool = False) -> None:
101
101
  """Populate CRUD permissions using class-level defaults and overrides."""
102
102
  default_read = ["public"]
103
103
  default_write = ["isAuthenticated"]
@@ -111,7 +111,7 @@ class ManagerBasedPermission(BasePermission):
111
111
  self.__update__ = getattr(self.__class__, "__update__", default_write)
112
112
  self.__delete__ = getattr(self.__class__, "__delete__", default_write)
113
113
 
114
- def __getBasedOnPermission(self) -> Optional[BasePermission]:
114
+ def __get_based_on_permission(self) -> Optional[BasePermission]:
115
115
  """
116
116
  Resolve and return a BasePermission instance from the manager attribute named by the class-level `__based_on__` configuration.
117
117
 
@@ -124,7 +124,7 @@ class ManagerBasedPermission(BasePermission):
124
124
  InvalidBasedOnConfigurationError: If the configured `__based_on__` attribute does not exist on the target instance.
125
125
  InvalidBasedOnTypeError: If the configured attribute exists but does not resolve to a `GeneralManager` or subclass.
126
126
  """
127
- from general_manager.manager.generalManager import GeneralManager
127
+ from general_manager.manager.general_manager import GeneralManager
128
128
 
129
129
  __based_on__ = self.__based_on__
130
130
  if __based_on__ is None:
@@ -134,7 +134,7 @@ class ManagerBasedPermission(BasePermission):
134
134
  if basis_object is notExistent:
135
135
  raise InvalidBasedOnConfigurationError(__based_on__)
136
136
  if basis_object is None:
137
- self.__setPermissions(skip_based_on=True)
137
+ self.__set_permissions(skip_based_on=True)
138
138
  return None
139
139
  if not isinstance(basis_object, GeneralManager) and not (
140
140
  isinstance(basis_object, type) and issubclass(basis_object, GeneralManager)
@@ -154,7 +154,7 @@ class ManagerBasedPermission(BasePermission):
154
154
  request_user=self.request_user,
155
155
  )
156
156
 
157
- def __getAttributePermissions(
157
+ def __get_attribute_permissions(
158
158
  self,
159
159
  ) -> dict[str, dict[permission_type, list[str]]]:
160
160
  """Collect attribute-level permission overrides defined on the class."""
@@ -164,7 +164,7 @@ class ManagerBasedPermission(BasePermission):
164
164
  attribute_permissions[attribute] = getattr(self, attribute)
165
165
  return attribute_permissions
166
166
 
167
- def checkPermission(
167
+ def check_permission(
168
168
  self,
169
169
  action: permission_type,
170
170
  attribute: str,
@@ -184,7 +184,7 @@ class ManagerBasedPermission(BasePermission):
184
184
  """
185
185
  if (
186
186
  self.__based_on_permission
187
- and not self.__based_on_permission.checkPermission(action, attribute)
187
+ and not self.__based_on_permission.check_permission(action, attribute)
188
188
  ):
189
189
  return False
190
190
 
@@ -210,15 +210,15 @@ class ManagerBasedPermission(BasePermission):
210
210
  return last_result
211
211
  attribute_permission = True
212
212
  else:
213
- attribute_permission = self.__checkSpecificPermission(
213
+ attribute_permission = self.__check_specific_permission(
214
214
  self.__attribute_permissions[attribute][action]
215
215
  )
216
216
 
217
- permission = self.__checkSpecificPermission(permissions)
217
+ permission = self.__check_specific_permission(permissions)
218
218
  self.__overall_results[action] = permission
219
219
  return permission and attribute_permission
220
220
 
221
- def __checkSpecificPermission(
221
+ def __check_specific_permission(
222
222
  self,
223
223
  permissions: list[str],
224
224
  ) -> bool:
@@ -226,17 +226,17 @@ class ManagerBasedPermission(BasePermission):
226
226
  if not permissions:
227
227
  return True
228
228
  for permission in permissions:
229
- if self.validatePermissionString(permission):
229
+ if self.validate_permission_string(permission):
230
230
  return True
231
231
  return False
232
232
 
233
- def getPermissionFilter(
233
+ def get_permission_filter(
234
234
  self,
235
235
  ) -> list[dict[Literal["filter", "exclude"], dict[str, str]]]:
236
236
  """
237
237
  Builds queryset filter and exclude mappings derived from this permission configuration.
238
238
 
239
- If a based-on permission exists, its filters and excludes are included with each key prefixed by the name in __based_on__. Then appends filters produced from this class's read permissions via _getPermissionFilter.
239
+ If a based-on permission exists, its filters and excludes are included with each key prefixed by the name in __based_on__. Then appends filters produced from this class's read permissions via _get_permission_filter.
240
240
 
241
241
  Returns:
242
242
  list[dict[Literal["filter", "exclude"], dict[str, str]]]: A list of dictionaries each containing "filter" and "exclude" mappings where keys are queryset lookups and values are lookup values.
@@ -245,7 +245,7 @@ class ManagerBasedPermission(BasePermission):
245
245
  filters: list[dict[Literal["filter", "exclude"], dict[str, str]]] = []
246
246
 
247
247
  if self.__based_on_permission is not None:
248
- base_permissions = self.__based_on_permission.getPermissionFilter()
248
+ base_permissions = self.__based_on_permission.get_permission_filter()
249
249
  for base_permission in base_permissions:
250
250
  filter = base_permission.get("filter", {})
251
251
  exclude = base_permission.get("exclude", {})
@@ -263,6 +263,6 @@ class ManagerBasedPermission(BasePermission):
263
263
  )
264
264
 
265
265
  for permission in self.__read__:
266
- filters.append(self._getPermissionFilter(permission))
266
+ filters.append(self._get_permission_filter(permission))
267
267
 
268
268
  return filters
@@ -3,13 +3,13 @@
3
3
  from __future__ import annotations
4
4
  from django.contrib.auth.models import AbstractUser, AnonymousUser
5
5
  from typing import Any
6
- from general_manager.permission.basePermission import (
6
+ from general_manager.permission.base_permission import (
7
7
  BasePermission,
8
8
  PermissionCheckError,
9
9
  )
10
10
 
11
- from general_manager.permission.permissionDataManager import PermissionDataManager
12
- from general_manager.permission.utils import validatePermissionString
11
+ from general_manager.permission.permission_data_manager import PermissionDataManager
12
+ from general_manager.permission.utils import validate_permission_string
13
13
 
14
14
 
15
15
  class MutationPermission:
@@ -29,7 +29,7 @@ class MutationPermission:
29
29
  """
30
30
  self._data: PermissionDataManager = PermissionDataManager(data)
31
31
  self._request_user = request_user
32
- self.__attribute_permissions = self.__getAttributePermissions()
32
+ self.__attribute_permissions = self.__get_attribute_permissions()
33
33
 
34
34
  self.__overall_result: bool | None = None
35
35
 
@@ -43,7 +43,7 @@ class MutationPermission:
43
43
  """Return the user whose permissions are being evaluated."""
44
44
  return self._request_user
45
45
 
46
- def __getAttributePermissions(
46
+ def __get_attribute_permissions(
47
47
  self,
48
48
  ) -> dict[str, list[str]]:
49
49
  """Collect attribute-specific permission expressions declared on the class."""
@@ -71,17 +71,17 @@ class MutationPermission:
71
71
  """
72
72
  errors = []
73
73
  if not isinstance(request_user, (AbstractUser, AnonymousUser)):
74
- request_user = BasePermission.getUserWithId(request_user)
74
+ request_user = BasePermission.get_user_with_id(request_user)
75
75
  Permission = cls(data, request_user)
76
76
  for key in data:
77
- if not Permission.checkPermission(key):
77
+ if not Permission.check_permission(key):
78
78
  errors.append(
79
79
  f"Permission denied for {key} with value {data[key]} for user {request_user}"
80
80
  )
81
81
  if errors:
82
82
  raise PermissionCheckError(request_user, errors)
83
83
 
84
- def checkPermission(
84
+ def check_permission(
85
85
  self,
86
86
  attribute: str,
87
87
  ) -> bool:
@@ -105,20 +105,20 @@ class MutationPermission:
105
105
  return last_result
106
106
  attribute_permission = True
107
107
  else:
108
- attribute_permission = self.__checkSpecificPermission(
108
+ attribute_permission = self.__check_specific_permission(
109
109
  self.__attribute_permissions[attribute]
110
110
  )
111
111
 
112
- permission = self.__checkSpecificPermission(self.__mutate__)
112
+ permission = self.__check_specific_permission(self.__mutate__)
113
113
  self.__overall_result = permission
114
114
  return permission and attribute_permission
115
115
 
116
- def __checkSpecificPermission(
116
+ def __check_specific_permission(
117
117
  self,
118
118
  permissions: list[str],
119
119
  ) -> bool:
120
120
  """Return True when any permission expression evaluates to True."""
121
121
  for permission in permissions:
122
- if validatePermissionString(permission, self.data, self.request_user):
122
+ if validate_permission_string(permission, self.data, self.request_user):
123
123
  return True
124
124
  return False
@@ -4,10 +4,10 @@ from typing import Any, Callable, TYPE_CHECKING, TypedDict, Literal
4
4
 
5
5
  if TYPE_CHECKING:
6
6
  from django.contrib.auth.models import AbstractUser, AnonymousUser
7
- from general_manager.permission.permissionDataManager import (
7
+ from general_manager.permission.permission_data_manager import (
8
8
  PermissionDataManager,
9
9
  )
10
- from general_manager.manager.generalManager import GeneralManager
10
+ from general_manager.manager.general_manager import GeneralManager
11
11
  from general_manager.manager.meta import GeneralManagerMeta
12
12
 
13
13