GeneralManager 0.10.5__py3-none-any.whl → 0.10.6__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.
@@ -102,9 +102,9 @@ class GraphQL:
102
102
  @classmethod
103
103
  def createGraphqlInterface(cls, generalManagerClass: GeneralManagerMeta) -> None:
104
104
  """
105
- Generates and registers a GraphQL ObjectType for a given GeneralManager class.
105
+ Generates and registers a GraphQL ObjectType for the specified GeneralManager class.
106
106
 
107
- This method maps interface and GraphQLProperty attributes to Graphene fields, creates resolvers for each field, registers the resulting type in the internal registry, and adds corresponding query fields to the schema.
107
+ This method maps interface attributes and GraphQLProperty fields to Graphene fields, creates appropriate resolvers, registers the resulting type in the internal registry, and adds related query fields to the schema.
108
108
  """
109
109
  interface_cls: InterfaceBase | None = getattr(
110
110
  generalManagerClass, "Interface", None
@@ -143,10 +143,12 @@ class GraphQL:
143
143
  @staticmethod
144
144
  def _sortByOptions(
145
145
  generalManagerClass: GeneralManagerMeta,
146
- ) -> type[graphene.Enum]:
146
+ ) -> type[graphene.Enum] | None:
147
147
  """
148
- Erzeugt ein Enum für Sortieroptionen basierend auf den Attributstypen der
149
- Manager-Klasse.
148
+ Creates a Graphene Enum type representing sortable fields for a given GeneralManager class.
149
+
150
+ Returns:
151
+ A Graphene Enum type with options for each sortable attribute, or None if no sortable fields exist.
150
152
  """
151
153
  sort_options = []
152
154
  for (
@@ -162,6 +164,9 @@ class GraphQL:
162
164
  else:
163
165
  sort_options.append(field_name)
164
166
 
167
+ if not sort_options:
168
+ return None
169
+
165
170
  return type(
166
171
  f"{generalManagerClass.__name__}SortByOptions",
167
172
  (graphene.Enum,),
@@ -169,9 +174,13 @@ class GraphQL:
169
174
  )
170
175
 
171
176
  @staticmethod
172
- def _createFilterOptions(field_name: str, field_type: GeneralManagerMeta) -> type:
177
+ def _createFilterOptions(
178
+ field_name: str, field_type: GeneralManagerMeta
179
+ ) -> type[graphene.InputObjectType] | None:
173
180
  """
174
- Baut dynamisch ein InputObjectType für Filteroptionen auf.
181
+ Dynamically generates a Graphene InputObjectType for filtering fields of a GeneralManager subclass.
182
+
183
+ Creates filter fields for each attribute based on its type, supporting numeric and string filter options, as well as specialized handling for Measurement attributes. Returns the generated InputObjectType or None if no filter fields are applicable.
175
184
  """
176
185
  number_options = ["exact", "gt", "gte", "lt", "lte"]
177
186
  string_options = [
@@ -212,6 +221,8 @@ class GraphQL:
212
221
  filter_fields[f"{attr_name}__{option}"] = (
213
222
  GraphQL._mapFieldToGrapheneRead(attr_type, attr_name)
214
223
  )
224
+ if not filter_fields:
225
+ return None
215
226
 
216
227
  filter_class = type(
217
228
  graphene_filter_type_name,
@@ -223,21 +234,32 @@ class GraphQL:
223
234
 
224
235
  @staticmethod
225
236
  def _mapFieldToGrapheneRead(field_type: type, field_name: str) -> Any:
237
+ """
238
+ Maps a Python field type and name to the appropriate Graphene field for GraphQL schema generation.
239
+
240
+ For `Measurement` types, returns a field with an optional `target_unit` argument. For `GeneralManager` subclasses, returns either a list field (with optional filtering, exclusion, sorting, pagination, and grouping arguments if available) or a single field, depending on the field name. For other types, returns the corresponding Graphene scalar field.
241
+ """
226
242
  if issubclass(field_type, Measurement):
227
243
  return graphene.Field(MeasurementType, target_unit=graphene.String())
228
244
  elif issubclass(field_type, GeneralManager):
229
245
  if field_name.endswith("_list"):
246
+ attributes = {
247
+ "reverse": graphene.Boolean(),
248
+ "page": graphene.Int(),
249
+ "page_size": graphene.Int(),
250
+ "group_by": graphene.List(graphene.String),
251
+ }
230
252
  filter_options = GraphQL._createFilterOptions(field_name, field_type)
253
+ if filter_options:
254
+ attributes["filter"] = filter_options()
255
+ attributes["exclude"] = filter_options()
256
+
231
257
  sort_by_options = GraphQL._sortByOptions(field_type)
258
+ if sort_by_options:
259
+ attributes["sort_by"] = sort_by_options()
232
260
  return graphene.List(
233
261
  lambda: GraphQL.graphql_type_registry[field_type.__name__],
234
- filter=filter_options(),
235
- exclude=filter_options(),
236
- sort_by=sort_by_options(),
237
- reverse=graphene.Boolean(),
238
- page=graphene.Int(),
239
- page_size=graphene.Int(),
240
- group_by=graphene.List(graphene.String),
262
+ **attributes,
241
263
  )
242
264
  return graphene.Field(
243
265
  lambda: GraphQL.graphql_type_registry[field_type.__name__]
@@ -348,7 +370,14 @@ class GraphQL:
348
370
  base_getter: Callable[[Any], Any], fallback_manager_class: type[GeneralManager]
349
371
  ) -> Callable[..., Any]:
350
372
  """
351
- Returns a resolver function for GraphQL list fields that retrieves a queryset, applies permission-based filtering, query filters, sorting, pagination, and optional grouping, and returns the resulting data.
373
+ Create a resolver function for GraphQL list fields that retrieves and returns a queryset with permission filters, query filters, sorting, pagination, and optional grouping applied.
374
+
375
+ Parameters:
376
+ base_getter: Function to obtain the base queryset from the parent instance.
377
+ fallback_manager_class: Manager class to use if the queryset does not specify one.
378
+
379
+ Returns:
380
+ A resolver function that processes list queries with filtering, sorting, pagination, and grouping.
352
381
  """
353
382
 
354
383
  def resolver(
@@ -363,7 +392,7 @@ class GraphQL:
363
392
  group_by: list[str] | None = None,
364
393
  ) -> Any:
365
394
  """
366
- Resolves a list field by returning a queryset filtered by permissions, query parameters, sorting, pagination, and optional grouping.
395
+ Resolves a list field by returning a queryset with permission filters, query filters, sorting, pagination, and optional grouping applied.
367
396
 
368
397
  Parameters:
369
398
  filter: Filter criteria as a dictionary or JSON string.
@@ -375,7 +404,7 @@ class GraphQL:
375
404
  group_by: List of field names to group results by.
376
405
 
377
406
  Returns:
378
- A queryset with applied permission filters, filtering, sorting, pagination, and grouping.
407
+ The resulting queryset after applying permissions, filters, sorting, pagination, and grouping.
379
408
  """
380
409
  base_queryset = base_getter(self)
381
410
  # use _manager_class from the attribute if available, otherwise fallback
@@ -451,9 +480,9 @@ class GraphQL:
451
480
  cls, graphene_type: type, generalManagerClass: GeneralManagerMeta
452
481
  ) -> None:
453
482
  """
454
- Adds list and single-item query fields for a GeneralManager-derived class to the GraphQL schema.
483
+ Add list and single-item query fields for a GeneralManager subclass to the GraphQL schema.
455
484
 
456
- Registers a list query supporting filtering, sorting, pagination, and grouping, as well as a single-item query using identification fields for the specified manager class. The corresponding resolvers are attached to the schema.
485
+ Registers a list query field with optional filtering, exclusion, sorting, pagination, and grouping arguments, as well as a single-item query field using identification fields from the manager's interface. Attaches the corresponding resolvers for both queries to the schema.
457
486
  """
458
487
  if not issubclass(generalManagerClass, GeneralManager):
459
488
  raise TypeError(
@@ -465,19 +494,24 @@ class GraphQL:
465
494
 
466
495
  # resolver and field for the list query
467
496
  list_field_name = f"{generalManagerClass.__name__.lower()}_list"
497
+ attributes = {
498
+ "reverse": graphene.Boolean(),
499
+ "page": graphene.Int(),
500
+ "page_size": graphene.Int(),
501
+ "group_by": graphene.List(graphene.String),
502
+ }
468
503
  filter_options = cls._createFilterOptions(
469
504
  generalManagerClass.__name__.lower(), generalManagerClass
470
505
  )
506
+ if filter_options:
507
+ attributes["filter"] = filter_options()
508
+ attributes["exclude"] = filter_options()
471
509
  sort_by_options = cls._sortByOptions(generalManagerClass)
510
+ if sort_by_options:
511
+ attributes["sort_by"] = sort_by_options()
472
512
  list_field = graphene.List(
473
513
  graphene_type,
474
- filter=filter_options(),
475
- exclude=filter_options(),
476
- sort_by=sort_by_options(),
477
- reverse=graphene.Boolean(),
478
- page=graphene.Int(),
479
- page_size=graphene.Int(),
480
- group_by=graphene.List(graphene.String),
514
+ **attributes,
481
515
  )
482
516
 
483
517
  list_resolver = cls._createListResolver(
@@ -519,7 +553,7 @@ class GraphQL:
519
553
  """
520
554
  Generate a dictionary of Graphene input fields for mutations based on the attributes of the provided interface class.
521
555
 
522
- Skips system-managed fields and derived attributes. For attributes referencing `GeneralManager` subclasses, uses 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. Adds an optional `history_comment` field marked as editable.
556
+ 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. An optional `history_comment` field, also marked as editable, is always included.
523
557
 
524
558
  Returns:
525
559
  dict[str, Any]: Mapping of attribute names to Graphene input fields for mutation arguments.
@@ -572,12 +606,12 @@ class GraphQL:
572
606
  default_return_values: dict[str, Any],
573
607
  ) -> type[graphene.Mutation] | None:
574
608
  """
575
- Dynamically generates a Graphene mutation class for creating an instance of the specified GeneralManager subclass.
609
+ Dynamically generates a Graphene mutation class for creating an instance of a specified GeneralManager subclass.
576
610
 
577
- The generated mutation class includes a `mutate` method that filters out fields with `NOT_PROVIDED` values, invokes the manager's `create` method with the provided arguments and the current user's ID, and returns a dictionary indicating success, any errors, and the created instance. Returns None if the manager class does not define an interface.
611
+ The generated mutation class filters out fields with `NOT_PROVIDED` values, calls the manager's `create` method with the provided arguments and the current user's ID, and returns a dictionary containing a success flag, any errors, and the created instance. Returns None if the manager class does not define an interface.
578
612
 
579
613
  Returns:
580
- The generated Graphene mutation class, or None if no interface is defined for the manager class.
614
+ The generated Graphene mutation class, or None if the manager class does not define an interface.
581
615
  """
582
616
  interface_cls: InterfaceBase | None = getattr(
583
617
  generalManagerClass, "Interface", None
@@ -591,9 +625,9 @@ class GraphQL:
591
625
  **kwargs: Any,
592
626
  ) -> dict:
593
627
  """
594
- Creates a new instance of the manager class with the provided arguments.
628
+ Create a new instance of the manager class using the provided arguments.
595
629
 
596
- Filters out fields with values marked as `NOT_PROVIDED` before creation. Returns a dictionary containing a success flag, a list of errors (if any), and the created instance under a key named after the manager class.
630
+ Filters out any fields with values set to `NOT_PROVIDED` before invoking the creation method. Returns a dictionary with a success flag, a list of errors if creation fails, and the created instance keyed by the manager class name.
597
631
  """
598
632
  try:
599
633
  kwargs = {
@@ -644,9 +678,9 @@ class GraphQL:
644
678
  default_return_values: dict[str, Any],
645
679
  ) -> type[graphene.Mutation] | None:
646
680
  """
647
- Generates a GraphQL mutation class for updating instances of a GeneralManager subclass.
681
+ Generates a GraphQL mutation class for updating an instance of a GeneralManager subclass.
648
682
 
649
- The generated mutation accepts editable fields as arguments, invokes the manager's `update` method with the provided values, and returns a dictionary indicating success, any errors, and the updated instance. Returns None if the manager class does not define an `Interface`.
683
+ The generated mutation accepts editable fields as arguments, calls the manager's `update` method with the provided values and the current user's ID, and returns a dictionary containing the operation's success status, any error messages, and the updated instance. Returns None if the manager class does not define an `Interface`.
650
684
 
651
685
  Returns:
652
686
  The generated Graphene mutation class, or None if no interface is defined.
@@ -663,14 +697,14 @@ class GraphQL:
663
697
  **kwargs: Any,
664
698
  ) -> dict:
665
699
  """
666
- Performs an update mutation on a GeneralManager instance with the specified fields.
700
+ Updates a GeneralManager instance with the provided fields.
667
701
 
668
702
  Parameters:
669
703
  info (GraphQLResolveInfo): The GraphQL resolver context, typically containing user and request information.
670
704
  **kwargs: Fields to update, including the required 'id' of the instance.
671
705
 
672
706
  Returns:
673
- dict: Contains the operation's success status, a list of error messages if any, and the updated instance keyed by its class name.
707
+ dict: A dictionary with keys 'success' (bool), 'errors' (list of str), and the updated instance keyed by its class name.
674
708
  """
675
709
  try:
676
710
  manager_id = kwargs.pop("id", None)
@@ -716,9 +750,12 @@ class GraphQL:
716
750
  default_return_values: dict[str, Any],
717
751
  ) -> type[graphene.Mutation] | None:
718
752
  """
719
- Generates a GraphQL mutation class for deleting (deactivating) an instance of a GeneralManager subclass.
753
+ Generates a GraphQL mutation class for deactivating (soft-deleting) an instance of a GeneralManager subclass.
754
+
755
+ The generated mutation accepts input fields defined by the manager's interface, deactivates the specified instance using its ID, and returns a dictionary containing the operation's success status, any error messages, and the deactivated instance keyed by the class name.
720
756
 
721
- The generated mutation accepts input fields defined in the manager's interface, deactivates the specified instance using its ID, and returns a dictionary with the operation's success status, any error messages, and the deactivated instance.
757
+ Returns:
758
+ The generated Graphene mutation class, or None if the manager class does not define an interface.
722
759
  """
723
760
  interface_cls: InterfaceBase | None = getattr(
724
761
  generalManagerClass, "Interface", None
@@ -732,10 +769,13 @@ class GraphQL:
732
769
  **kwargs: Any,
733
770
  ) -> dict:
734
771
  """
735
- Deactivates an instance of the specified GeneralManager class and returns the result.
772
+ Deactivates an instance of the specified GeneralManager class and returns the operation result.
736
773
 
737
774
  Returns:
738
- dict: Contains the operation's success status, a list of error messages if any, and the deactivated instance keyed by the class name.
775
+ dict: A dictionary with keys:
776
+ - "success": Boolean indicating if the operation was successful.
777
+ - "errors": List of error messages, empty if successful.
778
+ - <ClassName>: The deactivated instance, keyed by the class name.
739
779
  """
740
780
  try:
741
781
  manager_id = kwargs.pop("id", None)
@@ -228,18 +228,18 @@ class Measurement:
228
228
 
229
229
  def __mul__(self, other: Any) -> Measurement:
230
230
  """
231
- Returns the product of this measurement and another measurement or numeric value.
232
-
233
- Multiplication between two currency measurements is not permitted. When multiplied by another measurement, the result combines their units. When multiplied by a numeric value, the magnitude is scaled and the unit remains unchanged.
234
-
231
+ Multiply this measurement by another measurement or a numeric value.
232
+
233
+ Multiplying two currency measurements is not allowed. When multiplying by another measurement, the resulting measurement combines their units. When multiplying by a numeric value, only the magnitude is scaled.
234
+
235
235
  Returns:
236
- Measurement: A new Measurement representing the result.
237
-
236
+ Measurement: The result of the multiplication.
237
+
238
238
  Raises:
239
- TypeError: If multiplying two currency measurements or if the operand is neither a Measurement nor a numeric value.
239
+ TypeError: If both operands are currency measurements, or if the operand is not a Measurement or numeric value.
240
240
  """
241
241
  if isinstance(other, Measurement):
242
- if self.is_currency() or other.is_currency():
242
+ if self.is_currency() and other.is_currency():
243
243
  raise TypeError(
244
244
  "Multiplication between two currency amounts is not allowed."
245
245
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.10.5
3
+ Version: 0.10.6
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License-Expression: MIT
@@ -1,6 +1,6 @@
1
1
  general_manager/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  general_manager/apps.py,sha256=ii-48klC2kBRjxtdQU9-RtPq66lZ8fDa7BmqyH-mbzk,9904
3
- general_manager/api/graphql.py,sha256=N7UbhLA2RGfzE8GCt8Ld_sQ-yiQTxAAnO0Qt8nBLWlg,31171
3
+ general_manager/api/graphql.py,sha256=jpdtaep_ql94krsVvGJRpuqT-MR6iZCFpezeJAl4Mlw,33382
4
4
  general_manager/api/mutation.py,sha256=RvKp4OnV70q4Dqmu407Cd0FXgD12WdbRgzYCS4qd_bg,5990
5
5
  general_manager/api/property.py,sha256=oc93p1P8dcIvrNorRuqD1EJVsd6eYttYhZuAS0s28gs,696
6
6
  general_manager/bucket/baseBucket.py,sha256=UjEai7cVxgDJysoVY2-7s3YULW7bi-sx2mPqRKFWyTw,7728
@@ -29,7 +29,7 @@ general_manager/manager/groupManager.py,sha256=8dpZUfm7aFL4lraUWv4qbbDRClQZaYxw4
29
29
  general_manager/manager/input.py,sha256=-pJXGJ-g2-OxZfl4Buj3mQkf05fN4p8MsR2Lh9BQcEo,3208
30
30
  general_manager/manager/meta.py,sha256=-9celpo-oZmkTb8TnHfvcd_4XWTy1cn2UO-jp13NFmQ,6387
31
31
  general_manager/measurement/__init__.py,sha256=X97meFujBldE5v0WMF7SmKeGpC5R0JTczfLo_Lq1Xek,84
32
- general_manager/measurement/measurement.py,sha256=emd1z3IDClK7nrIrUL_JXPxNhJEq2HnXq6qNYv9ubcM,16090
32
+ general_manager/measurement/measurement.py,sha256=T3R2qqDkqPY_91DzN0zJF4ug62aCNyN5-75WE9Tm7ko,16067
33
33
  general_manager/measurement/measurementField.py,sha256=ixkZR_t--HGckK2iYi6sXOOa_Vbni4QRxK5Ngmy5YKc,6863
34
34
  general_manager/permission/__init__.py,sha256=5UlDERN60Vn8obGVkT-cOM8kHjzmoxgK5w5FgTCDhGE,59
35
35
  general_manager/permission/basePermission.py,sha256=14iKo6qVmaUdg1sAz-gSZyNtpVKAAapIhutVAMDf93c,6056
@@ -49,8 +49,8 @@ general_manager/utils/makeCacheKey.py,sha256=UlFsxHXgsYy69AAelkF6GDvY4h7AImT2bBn
49
49
  general_manager/utils/noneToZero.py,sha256=KfQtMQnrT6vsYST0K7lv6pVujkDcK3XL8czHYOhgqKQ,539
50
50
  general_manager/utils/pathMapping.py,sha256=nrz5owQg2a69Yig1eCXorR9U0NSw7NmBAk5OkeoHTdA,6842
51
51
  general_manager/utils/testing.py,sha256=ElZ8p4iZHxsHjDN8Lm5TmI6527CW747ltDOmtY6gAhk,11872
52
- generalmanager-0.10.5.dist-info/licenses/LICENSE,sha256=YGFm0ieb4KpkMRRt2qnWue6uFh0cUMtobwEBkHwajhc,1450
53
- generalmanager-0.10.5.dist-info/METADATA,sha256=J4d2QlGnTmwb45tsUO0gGrcphQRym-xeRiJh-1-KwQA,6206
54
- generalmanager-0.10.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
- generalmanager-0.10.5.dist-info/top_level.txt,sha256=sTDtExP9ga-YP3h3h42yivUY-A2Q23C2nw6LNKOho4I,16
56
- generalmanager-0.10.5.dist-info/RECORD,,
52
+ generalmanager-0.10.6.dist-info/licenses/LICENSE,sha256=YGFm0ieb4KpkMRRt2qnWue6uFh0cUMtobwEBkHwajhc,1450
53
+ generalmanager-0.10.6.dist-info/METADATA,sha256=SrGKXDLzzs69odSsBd3t7pE4DIuVS9lmlkyhbnAYgus,6206
54
+ generalmanager-0.10.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
+ generalmanager-0.10.6.dist-info/top_level.txt,sha256=sTDtExP9ga-YP3h3h42yivUY-A2Q23C2nw6LNKOho4I,16
56
+ generalmanager-0.10.6.dist-info/RECORD,,