GeneralManager 0.14.0__py3-none-any.whl → 0.15.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.
Files changed (63) hide show
  1. general_manager/__init__.py +49 -0
  2. general_manager/api/__init__.py +36 -0
  3. general_manager/api/graphql.py +92 -43
  4. general_manager/api/mutation.py +35 -10
  5. general_manager/api/property.py +26 -3
  6. general_manager/apps.py +23 -16
  7. general_manager/bucket/__init__.py +32 -0
  8. general_manager/bucket/baseBucket.py +76 -64
  9. general_manager/bucket/calculationBucket.py +188 -108
  10. general_manager/bucket/databaseBucket.py +130 -49
  11. general_manager/bucket/groupBucket.py +113 -60
  12. general_manager/cache/__init__.py +38 -0
  13. general_manager/cache/cacheDecorator.py +29 -17
  14. general_manager/cache/cacheTracker.py +34 -15
  15. general_manager/cache/dependencyIndex.py +117 -33
  16. general_manager/cache/modelDependencyCollector.py +17 -8
  17. general_manager/cache/signals.py +17 -6
  18. general_manager/factory/__init__.py +34 -5
  19. general_manager/factory/autoFactory.py +57 -60
  20. general_manager/factory/factories.py +39 -14
  21. general_manager/factory/factoryMethods.py +38 -1
  22. general_manager/interface/__init__.py +36 -0
  23. general_manager/interface/baseInterface.py +71 -27
  24. general_manager/interface/calculationInterface.py +18 -10
  25. general_manager/interface/databaseBasedInterface.py +102 -71
  26. general_manager/interface/databaseInterface.py +66 -20
  27. general_manager/interface/models.py +10 -4
  28. general_manager/interface/readOnlyInterface.py +44 -30
  29. general_manager/manager/__init__.py +36 -3
  30. general_manager/manager/generalManager.py +73 -47
  31. general_manager/manager/groupManager.py +72 -17
  32. general_manager/manager/input.py +23 -15
  33. general_manager/manager/meta.py +53 -53
  34. general_manager/measurement/__init__.py +37 -2
  35. general_manager/measurement/measurement.py +135 -58
  36. general_manager/measurement/measurementField.py +161 -61
  37. general_manager/permission/__init__.py +32 -1
  38. general_manager/permission/basePermission.py +29 -12
  39. general_manager/permission/managerBasedPermission.py +32 -26
  40. general_manager/permission/mutationPermission.py +32 -3
  41. general_manager/permission/permissionChecks.py +9 -1
  42. general_manager/permission/permissionDataManager.py +49 -15
  43. general_manager/permission/utils.py +14 -3
  44. general_manager/rule/__init__.py +27 -1
  45. general_manager/rule/handler.py +90 -5
  46. general_manager/rule/rule.py +40 -27
  47. general_manager/utils/__init__.py +44 -2
  48. general_manager/utils/argsToKwargs.py +17 -9
  49. general_manager/utils/filterParser.py +29 -30
  50. general_manager/utils/formatString.py +2 -0
  51. general_manager/utils/jsonEncoder.py +14 -1
  52. general_manager/utils/makeCacheKey.py +18 -12
  53. general_manager/utils/noneToZero.py +8 -6
  54. general_manager/utils/pathMapping.py +92 -29
  55. general_manager/utils/public_api.py +49 -0
  56. general_manager/utils/testing.py +135 -69
  57. {generalmanager-0.14.0.dist-info → generalmanager-0.15.0.dist-info}/METADATA +38 -4
  58. generalmanager-0.15.0.dist-info/RECORD +62 -0
  59. generalmanager-0.15.0.dist-info/licenses/LICENSE +21 -0
  60. generalmanager-0.14.0.dist-info/RECORD +0 -58
  61. generalmanager-0.14.0.dist-info/licenses/LICENSE +0 -29
  62. {generalmanager-0.14.0.dist-info → generalmanager-0.15.0.dist-info}/WHEEL +0 -0
  63. {generalmanager-0.14.0.dist-info → generalmanager-0.15.0.dist-info}/top_level.txt +0 -0
@@ -1,3 +1,5 @@
1
+ """Bucket implementation that enumerates calculation interface combinations."""
2
+
1
3
  from __future__ import annotations
2
4
  from types import UnionType
3
5
  from typing import (
@@ -11,6 +13,7 @@ from typing import (
11
13
  List,
12
14
  TypedDict,
13
15
  get_origin,
16
+ get_args,
14
17
  )
15
18
  from operator import attrgetter
16
19
  from copy import deepcopy
@@ -34,6 +37,8 @@ class SortedFilters(TypedDict):
34
37
 
35
38
 
36
39
  class CalculationBucket(Bucket[GeneralManagerType]):
40
+ """Bucket that builds cartesian products of calculation input fields."""
41
+
37
42
  def __init__(
38
43
  self,
39
44
  manager_class: Type[GeneralManagerType],
@@ -41,19 +46,22 @@ class CalculationBucket(Bucket[GeneralManagerType]):
41
46
  exclude_definitions: Optional[dict[str, dict]] = None,
42
47
  sort_key: Optional[Union[str, tuple[str]]] = None,
43
48
  reverse: bool = False,
44
- ):
49
+ ) -> None:
45
50
  """
46
- Initializes a CalculationBucket for managing calculation input combinations.
51
+ Prepare a calculation bucket that enumerates all input combinations.
47
52
 
48
- Args:
49
- manager_class: The manager class whose interface must inherit from CalculationInterface.
50
- filter_definitions: Optional filters to apply to input combinations.
51
- exclude_definitions: Optional exclusions to remove certain input combinations.
52
- sort_key: Optional key or tuple of keys to sort the generated combinations.
53
- reverse: If True, reverses the sorting order.
53
+ Parameters:
54
+ manager_class (type[GeneralManagerType]): Manager subclass whose interface derives from `CalculationInterface`.
55
+ filter_definitions (dict[str, dict] | None): Optional filter constraints applied to generated combinations.
56
+ exclude_definitions (dict[str, dict] | None): Optional exclude constraints removing combinations.
57
+ sort_key (str | tuple[str, ...] | None): Key(s) used to order generated combinations.
58
+ reverse (bool): When True, reverse the ordering defined by `sort_key`.
59
+
60
+ Returns:
61
+ None
54
62
 
55
63
  Raises:
56
- TypeError: If the manager class interface does not inherit from CalculationInterface.
64
+ TypeError: If the interface does not inherit from `CalculationInterface`.
57
65
  """
58
66
  from general_manager.interface.calculationInterface import (
59
67
  CalculationInterface,
@@ -88,10 +96,13 @@ class CalculationBucket(Bucket[GeneralManagerType]):
88
96
 
89
97
  def __eq__(self, other: object) -> bool:
90
98
  """
91
- Checks if this Bucket is equal to another by comparing class, data, and manager class.
99
+ Compare two calculation buckets for structural equality.
100
+
101
+ Parameters:
102
+ other (object): Candidate bucket.
92
103
 
93
104
  Returns:
94
- True if both objects are of the same class and have equal internal data and manager class; otherwise, False.
105
+ bool: True when both buckets share the same manager class and identical filter/exclude state.
95
106
  """
96
107
  if not isinstance(other, self.__class__):
97
108
  return False
@@ -103,10 +114,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
103
114
 
104
115
  def __reduce__(self) -> generalManagerClassName | tuple[Any, ...]:
105
116
  """
106
- Prepares the CalculationBucket instance for pickling by returning its reconstruction data.
117
+ Provide pickling support for calculation buckets.
107
118
 
108
119
  Returns:
109
- A tuple containing the class and a tuple of initialization arguments needed to recreate the instance.
120
+ tuple[Any, ...]: Reconstruction data representing the class, arguments, and state.
110
121
  """
111
122
  return (
112
123
  self.__class__,
@@ -122,10 +133,13 @@ class CalculationBucket(Bucket[GeneralManagerType]):
122
133
 
123
134
  def __setstate__(self, state: dict[str, Any]) -> None:
124
135
  """
125
- Restores the CalculationBucket instance from its pickled state.
136
+ Restore the bucket after unpickling.
137
+
138
+ Parameters:
139
+ state (dict[str, Any]): Pickled state containing cached combination data.
126
140
 
127
- Args:
128
- state: A dictionary containing the state of the instance, including current combinations.
141
+ Returns:
142
+ None
129
143
  """
130
144
  self._data = state.get("data")
131
145
 
@@ -134,15 +148,16 @@ class CalculationBucket(Bucket[GeneralManagerType]):
134
148
  other: Bucket[GeneralManagerType] | GeneralManagerType,
135
149
  ) -> CalculationBucket[GeneralManagerType]:
136
150
  """
137
- Combine this CalculationBucket with another bucket or manager instance of the same manager class.
138
-
139
- If combined with a manager instance, returns a bucket filtered to that manager's identification. If combined with another CalculationBucket of the same manager class, returns a new bucket containing only the filters and excludes that are present and identical in both buckets.
151
+ Merge two calculation buckets or intersect with a single manager instance.
140
152
 
141
- Raises:
142
- ValueError: If the other object is not a CalculationBucket or manager of the same class.
153
+ Parameters:
154
+ other (Bucket[GeneralManagerType] | GeneralManagerType): Calculation bucket or manager instance to merge.
143
155
 
144
156
  Returns:
145
- CalculationBucket[GeneralManagerType]: A new CalculationBucket representing the intersection of filters and excludes, or a filtered bucket for the given manager instance.
157
+ CalculationBucket[GeneralManagerType]: Bucket reflecting the combined constraints.
158
+
159
+ Raises:
160
+ ValueError: If `other` is incompatible or uses a different manager class.
146
161
  """
147
162
  from general_manager.manager.generalManager import GeneralManager
148
163
 
@@ -175,9 +190,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
175
190
 
176
191
  def __str__(self) -> str:
177
192
  """
178
- Returns a string representation of the bucket, listing up to five calculation manager instances with their input combinations.
193
+ Return a compact preview of the generated combinations.
179
194
 
180
- If more than five combinations exist, an ellipsis is appended to indicate additional entries.
195
+ Returns:
196
+ str: Human-readable summary of up to five combinations.
181
197
  """
182
198
  PRINT_MAX = 5
183
199
  combinations = self.generate_combinations()
@@ -196,7 +212,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
196
212
 
197
213
  def __repr__(self) -> str:
198
214
  """
199
- Returns a concise string representation of the CalculationBucket, including the manager class name, filters, excludes, sort key, and sort order.
215
+ Return a detailed representation of the bucket configuration.
216
+
217
+ Returns:
218
+ str: Debug string listing filters, excludes, sort key, and ordering.
200
219
  """
201
220
  return f"{self.__class__.__name__}({self._manager_class.__name__}, {self.filter_definitions}, {self.exclude_definitions}, {self.sort_key}, {self.reverse})"
202
221
 
@@ -205,40 +224,51 @@ class CalculationBucket(Bucket[GeneralManagerType]):
205
224
  properties: dict[str, GraphQLProperty], input_fields: dict[str, Input]
206
225
  ) -> dict[str, Input]:
207
226
  """
208
- Returns a dictionary of possible values for each input field based on the provided properties.
209
-
210
- This method analyzes the properties and input fields to determine valid values for each input parameter.
227
+ Derive input-field definitions for GraphQL properties without explicit inputs.
211
228
 
212
- Args:
213
- properties (dict[str, Any]): The GraphQL properties of the manager class.
214
- input_fields (dict[str, Any]): The input fields to analyze.
229
+ Parameters:
230
+ properties (dict[str, GraphQLProperty]): GraphQL properties declared on the manager.
231
+ input_fields (dict[str, Input]): Existing input field definitions.
215
232
 
216
233
  Returns:
217
- dict[str, Any]: A dictionary mapping input field names to their possible values.
234
+ dict[str, Input]: Combined mapping of input field names to `Input` definitions.
218
235
  """
219
236
  parsed_inputs = {**input_fields}
220
237
  for prop_name, prop in properties.items():
221
- type_hint = prop.graphql_type_hint
222
- origin = get_origin(type_hint)
238
+ current_hint = prop.graphql_type_hint
239
+ origin = get_origin(current_hint)
240
+ args = list(get_args(current_hint))
241
+
223
242
  if origin in (Union, UnionType):
224
- type_hint = type_hint.__args__[0] if type_hint.__args__ else str # type: ignore
243
+ non_none_args = [arg for arg in args if arg is not type(None)]
244
+ current_hint = non_none_args[0] if non_none_args else object
245
+ origin = get_origin(current_hint)
246
+ args = list(get_args(current_hint))
247
+
248
+ if origin in (list, tuple, set):
249
+ inner = args[0] if args else object
250
+ resolved_type = inner if isinstance(inner, type) else object
251
+ elif isinstance(current_hint, type):
252
+ resolved_type = current_hint
253
+ else:
254
+ resolved_type = object
225
255
 
226
- elif isinstance(type_hint, type) and issubclass(
227
- type_hint, (list, tuple, set, dict)
228
- ):
229
- type_hint: type = (
230
- type_hint.__args__[0] if hasattr(type_hint, "__args__") else str # type: ignore
231
- )
232
- prop_input = Input(type=type_hint, possible_values=None, depends_on=None)
256
+ prop_input = Input(
257
+ type=resolved_type, possible_values=None, depends_on=None
258
+ )
233
259
  parsed_inputs[prop_name] = prop_input
234
260
 
235
261
  return parsed_inputs
236
262
 
237
263
  def filter(self, **kwargs: Any) -> CalculationBucket:
238
264
  """
239
- Returns a new CalculationBucket with additional filters applied.
265
+ Add additional filters and return a new calculation bucket.
266
+
267
+ Parameters:
268
+ **kwargs (Any): Filter expressions applied to generated combinations.
240
269
 
241
- Merges the provided filter criteria with existing filters to further restrict valid input combinations.
270
+ Returns:
271
+ CalculationBucket: Bucket reflecting the updated filter definitions.
242
272
  """
243
273
  return CalculationBucket(
244
274
  manager_class=self._manager_class,
@@ -251,9 +281,13 @@ class CalculationBucket(Bucket[GeneralManagerType]):
251
281
 
252
282
  def exclude(self, **kwargs: Any) -> CalculationBucket:
253
283
  """
254
- Returns a new CalculationBucket with additional exclusion criteria applied.
284
+ Add additional exclusion rules and return a new calculation bucket.
285
+
286
+ Parameters:
287
+ **kwargs (Any): Exclusion expressions removing combinations from the result.
255
288
 
256
- Keyword arguments specify input values to exclude from the generated combinations.
289
+ Returns:
290
+ CalculationBucket: Bucket reflecting the updated exclusion definitions.
257
291
  """
258
292
  return CalculationBucket(
259
293
  manager_class=self._manager_class,
@@ -266,24 +300,34 @@ class CalculationBucket(Bucket[GeneralManagerType]):
266
300
 
267
301
  def all(self) -> CalculationBucket:
268
302
  """
269
- Return a deep copy of the current CalculationBucket instance.
270
-
271
- Use this method to obtain an independent copy of the bucket, ensuring that modifications to the returned instance do not affect the original.
303
+ Return a deep copy of this calculation bucket.
304
+
305
+ Returns:
306
+ CalculationBucket: Independent copy that can be mutated without affecting the original.
272
307
  """
273
308
  return deepcopy(self)
274
309
 
275
310
  def __iter__(self) -> Generator[GeneralManagerType, None, None]:
276
311
  """
277
- Iterate over all valid input combinations, yielding a manager instance for each.
278
-
312
+ Iterate over every generated combination as a manager instance.
313
+
279
314
  Yields:
280
- Manager instances created with each valid set of input parameters.
315
+ GeneralManagerType: Manager constructed from each valid set of inputs.
281
316
  """
282
317
  combinations = self.generate_combinations()
283
318
  for combo in combinations:
284
319
  yield self._manager_class(**combo)
285
320
 
286
321
  def _sortFilters(self, sorted_inputs: List[str]) -> SortedFilters:
322
+ """
323
+ Partition filters into input- and property-based buckets.
324
+
325
+ Parameters:
326
+ sorted_inputs (list[str]): Input names ordered by dependency.
327
+
328
+ Returns:
329
+ SortedFilters: Mapping that separates filters/excludes for inputs and properties.
330
+ """
287
331
  input_filters: dict[str, dict] = {}
288
332
  prop_filters: dict[str, dict] = {}
289
333
  input_excludes: dict[str, dict] = {}
@@ -309,10 +353,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
309
353
 
310
354
  def generate_combinations(self) -> List[dict[str, Any]]:
311
355
  """
312
- Generates and caches all valid input combinations based on filters, exclusions, and sorting.
356
+ Compute (and cache) the list of valid input combinations.
313
357
 
314
358
  Returns:
315
- A list of dictionaries, each representing a unique combination of input values that satisfy the current filters, exclusions, and sorting order.
359
+ list[dict[str, Any]]: Cached list of input dictionaries satisfying filters, excludes, and ordering.
316
360
  """
317
361
 
318
362
  def key_func(manager_obj: GeneralManagerType) -> tuple:
@@ -349,13 +393,13 @@ class CalculationBucket(Bucket[GeneralManagerType]):
349
393
 
350
394
  def topological_sort_inputs(self) -> List[str]:
351
395
  """
352
- Performs a topological sort of input fields based on their dependencies.
396
+ Produce a dependency-respecting order of input fields.
353
397
 
354
398
  Returns:
355
- A list of input field names ordered so that each field appears after its dependencies.
399
+ list[str]: Input names ordered so each dependency appears before dependants.
356
400
 
357
401
  Raises:
358
- ValueError: If a cyclic dependency is detected among the input fields.
402
+ ValueError: If the dependency graph contains a cycle.
359
403
  """
360
404
  from collections import defaultdict
361
405
 
@@ -370,16 +414,19 @@ class CalculationBucket(Bucket[GeneralManagerType]):
370
414
  visited = set()
371
415
  sorted_inputs = []
372
416
 
373
- def visit(node, temp_mark):
417
+ def visit(node: str, temp_mark: set[str]) -> None:
374
418
  """
375
- Performs a depth-first traversal to topologically sort nodes, detecting cycles.
419
+ Perform DFS while detecting cycles in the dependency graph.
376
420
 
377
- Args:
378
- node: The current node to visit.
379
- temp_mark: A set tracking nodes in the current traversal path to detect cycles.
421
+ Parameters:
422
+ node (str): Input field currently being processed.
423
+ temp_mark (set[str]): Nodes visited along the current path.
424
+
425
+ Returns:
426
+ None
380
427
 
381
428
  Raises:
382
- ValueError: If a cyclic dependency is detected involving the current node.
429
+ ValueError: If a cyclic dependency involves `node`.
383
430
  """
384
431
  if node in visited:
385
432
  return
@@ -402,22 +449,20 @@ class CalculationBucket(Bucket[GeneralManagerType]):
402
449
  def get_possible_values(
403
450
  self, key_name: str, input_field: Input, current_combo: dict
404
451
  ) -> Union[Iterable[Any], Bucket[Any]]:
405
- # Hole mögliche Werte
452
+ # Retrieve possible values
406
453
  """
407
- Retrieves the possible values for a given input field based on its definition and current dependencies.
408
-
409
- If the input field's `possible_values` is a callable, it is invoked with the current values of its dependencies. If it is an iterable or a `Bucket`, it is returned directly. Raises a `TypeError` if `possible_values` is not a valid type.
454
+ Resolve the potential values for an input field given the current combination.
410
455
 
411
- Args:
412
- key_name: The name of the input field.
413
- input_field: The input field object whose possible values are to be determined.
414
- current_combo: The current combination of input values, used to resolve dependencies.
456
+ Parameters:
457
+ key_name (str): Name of the input field.
458
+ input_field (Input): Input definition describing type and dependencies.
459
+ current_combo (dict): Current partial assignment of input values.
415
460
 
416
461
  Returns:
417
- An iterable or `Bucket` containing the possible values for the input field.
462
+ Iterable[Any] | Bucket[Any]: Collection of permissible values.
418
463
 
419
464
  Raises:
420
- TypeError: If `possible_values` is neither callable, iterable, nor a `Bucket`.
465
+ TypeError: If the configured `possible_values` cannot be evaluated.
421
466
  """
422
467
  if callable(input_field.possible_values):
423
468
  depends_on = input_field.depends_on
@@ -436,23 +481,30 @@ class CalculationBucket(Bucket[GeneralManagerType]):
436
481
  excludes: dict[str, dict],
437
482
  ) -> List[dict[str, Any]]:
438
483
  """
439
- Recursively generates all valid input combinations for the specified input fields, applying filters and exclusions.
484
+ Generate all valid input combinations while honouring filters and excludes.
440
485
 
441
- Args:
442
- sorted_inputs: Input field names ordered to respect dependency constraints.
443
- filters: Mapping of input field names to filter definitions.
444
- excludes: Mapping of input field names to exclusion definitions.
486
+ Parameters:
487
+ sorted_inputs (list[str]): Input names ordered by dependency.
488
+ filters (dict[str, dict]): Filter definitions keyed by input name.
489
+ excludes (dict[str, dict]): Exclusion definitions keyed by input name.
445
490
 
446
491
  Returns:
447
- A list of dictionaries, each representing a valid combination of input values that satisfy all filters and exclusions.
492
+ list[dict[str, Any]]: Valid input combinations.
448
493
  """
449
494
 
450
- def helper(index, current_combo):
495
+ def helper(
496
+ index: int,
497
+ current_combo: dict[str, Any],
498
+ ) -> Generator[dict[str, Any], None, None]:
451
499
  """
452
- Recursively generates all valid input combinations for calculation inputs.
500
+ Recursively emit input combinations that satisfy filters and excludes.
501
+
502
+ Parameters:
503
+ index (int): Position within `sorted_inputs` currently being assigned.
504
+ current_combo (dict[str, Any]): Partial assignment of inputs built so far.
453
505
 
454
506
  Yields:
455
- Dict[str, Any]: A dictionary representing a valid combination of input values, filtered and excluded according to the provided criteria.
507
+ dict[str, Any]: Completed combination of input values.
456
508
  """
457
509
  if index == len(sorted_inputs):
458
510
  yield current_combo.copy()
@@ -502,6 +554,17 @@ class CalculationBucket(Bucket[GeneralManagerType]):
502
554
  prop_filters: dict[str, Any],
503
555
  prop_excludes: dict[str, Any],
504
556
  ) -> list[GeneralManagerType]:
557
+ """
558
+ Apply property-level filters and excludes to manager combinations.
559
+
560
+ Parameters:
561
+ current_combos (list[dict[str, Any]]): Input combinations already passing input filters.
562
+ prop_filters (dict[str, Any]): Filter definitions keyed by property name.
563
+ prop_excludes (dict[str, Any]): Exclude definitions keyed by property name.
564
+
565
+ Returns:
566
+ list[GeneralManagerType]: Manager instances that satisfy property constraints.
567
+ """
505
568
 
506
569
  prop_filter_needed = set(prop_filters.keys()) | set(prop_excludes.keys())
507
570
  manager_combinations = [
@@ -537,7 +600,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
537
600
 
538
601
  def first(self) -> GeneralManagerType | None:
539
602
  """
540
- Returns the first generated manager instance, or None if no combinations exist.
603
+ Return the first generated manager instance.
604
+
605
+ Returns:
606
+ GeneralManagerType | None: First instance or None when no combinations exist.
541
607
  """
542
608
  try:
543
609
  return next(iter(self))
@@ -546,7 +612,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
546
612
 
547
613
  def last(self) -> GeneralManagerType | None:
548
614
  """
549
- Returns the last generated manager instance, or None if no combinations exist.
615
+ Return the last generated manager instance.
616
+
617
+ Returns:
618
+ GeneralManagerType | None: Last instance or None when no combinations exist.
550
619
  """
551
620
  items = list(self)
552
621
  if items:
@@ -555,13 +624,19 @@ class CalculationBucket(Bucket[GeneralManagerType]):
555
624
 
556
625
  def count(self) -> int:
557
626
  """
558
- Returns the number of calculation combinations in the bucket.
627
+ Return the number of calculation combinations.
628
+
629
+ Returns:
630
+ int: Number of generated combinations.
559
631
  """
560
632
  return self.__len__()
561
633
 
562
634
  def __len__(self) -> int:
563
635
  """
564
- Returns the number of generated calculation combinations in the bucket.
636
+ Return the number of generated combinations.
637
+
638
+ Returns:
639
+ int: Cached number of combinations.
565
640
  """
566
641
  return len(self.generate_combinations())
567
642
 
@@ -569,10 +644,14 @@ class CalculationBucket(Bucket[GeneralManagerType]):
569
644
  self, item: int | slice
570
645
  ) -> GeneralManagerType | CalculationBucket[GeneralManagerType]:
571
646
  """
572
- Returns a manager instance or a new bucket for the specified index or slice.
647
+ Retrieve a manager instance or subset of combinations.
648
+
649
+ Parameters:
650
+ item (int | slice): Index or slice specifying which combinations to return.
573
651
 
574
- If an integer index is provided, returns the corresponding manager instance.
575
- If a slice is provided, returns a new CalculationBucket representing the sliced subset.
652
+ Returns:
653
+ GeneralManagerType | CalculationBucket[GeneralManagerType]:
654
+ Manager instance for single indices or bucket wrapping the sliced combinations.
576
655
  """
577
656
  items = self.generate_combinations()
578
657
  result = items[item]
@@ -590,28 +669,28 @@ class CalculationBucket(Bucket[GeneralManagerType]):
590
669
 
591
670
  def __contains__(self, item: GeneralManagerType) -> bool:
592
671
  """
593
- Checks if the specified manager instance is present in the generated combinations.
672
+ Determine whether the provided manager instance exists among generated combinations.
594
673
 
595
- Args:
596
- item: The manager instance to check for membership.
674
+ Parameters:
675
+ item (GeneralManagerType): Manager instance to test for membership.
597
676
 
598
677
  Returns:
599
- True if the instance is among the generated combinations, False otherwise.
678
+ bool: True when the instance matches one of the generated combinations.
600
679
  """
601
680
  return any(item == mgr for mgr in self)
602
681
 
603
682
  def get(self, **kwargs: Any) -> GeneralManagerType:
604
683
  """
605
- Retrieves a single calculation manager instance matching the specified filters.
684
+ Retrieve a single manager instance that satisfies the given filters.
606
685
 
607
- Args:
608
- **kwargs: Filter criteria to apply.
686
+ Parameters:
687
+ **kwargs (Any): Filter expressions narrowing the calculation results.
609
688
 
610
689
  Returns:
611
- The unique manager instance matching the filters.
690
+ GeneralManagerType: Matching manager instance.
612
691
 
613
692
  Raises:
614
- ValueError: If no matching calculation is found or if multiple matches exist.
693
+ ValueError: If zero or multiple calculations match the filters.
615
694
  """
616
695
  filtered_bucket = self.filter(**kwargs)
617
696
  items = list(filtered_bucket)
@@ -626,14 +705,14 @@ class CalculationBucket(Bucket[GeneralManagerType]):
626
705
  self, key: str | tuple[str], reverse: bool = False
627
706
  ) -> CalculationBucket[GeneralManagerType]:
628
707
  """
629
- Return a new CalculationBucket instance with updated sorting criteria.
630
-
708
+ Return a new bucket with updated sorting preferences.
709
+
631
710
  Parameters:
632
- key (str or tuple of str): Field name(s) to sort the combinations by.
633
- reverse (bool): Whether to sort in descending order.
634
-
711
+ key (str | tuple[str, ...]): Attribute name(s) used for ordering combinations.
712
+ reverse (bool): Whether to apply descending order.
713
+
635
714
  Returns:
636
- CalculationBucket: A new bucket instance sorted according to the specified key and order.
715
+ CalculationBucket[GeneralManagerType]: Bucket configured with the provided sorting options.
637
716
  """
638
717
  return CalculationBucket(
639
718
  self._manager_class,
@@ -645,12 +724,13 @@ class CalculationBucket(Bucket[GeneralManagerType]):
645
724
 
646
725
  def none(self) -> CalculationBucket[GeneralManagerType]:
647
726
  """
648
- Return a new CalculationBucket instance of the same type containing no items.
649
-
650
- The returned bucket has all filters, excludes, and cached combinations cleared, representing an empty set of combinations.
727
+ Return an empty calculation bucket with the same configuration.
728
+
729
+ Returns:
730
+ CalculationBucket[GeneralManagerType]: Bucket with no combinations and cleared cached data.
651
731
  """
652
732
  own = self.all()
653
- own._current_combinations = None
733
+ own._data = []
654
734
  own.filters = {}
655
735
  own.excludes = {}
656
736
  return own