GeneralManager 0.19.2__py3-none-any.whl → 0.20.1__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.

@@ -19,10 +19,12 @@ from general_manager.rule.handler import (
19
19
  SumHandler,
20
20
  )
21
21
  from general_manager.manager.general_manager import GeneralManager
22
+ from general_manager.logging import get_logger
22
23
 
23
24
  GeneralManagerType = TypeVar("GeneralManagerType", bound=GeneralManager)
24
25
 
25
26
  NOTEXISTENT = object()
27
+ logger = get_logger("rule.engine")
26
28
 
27
29
 
28
30
  class NonexistentAttributeError(AttributeError):
@@ -131,6 +133,13 @@ class Rule(Generic[GeneralManagerType]):
131
133
  handler_cls: type[BaseRuleHandler] = import_string(path)
132
134
  inst = handler_cls()
133
135
  self._handlers[inst.function_name] = inst
136
+ logger.debug(
137
+ "initialised rule",
138
+ context={
139
+ "rule": self._func.__qualname__,
140
+ "variables": self._variables,
141
+ },
142
+ )
134
143
 
135
144
  @property
136
145
  def func(self) -> Callable[[GeneralManagerType], bool]:
@@ -173,12 +182,47 @@ class Rule(Generic[GeneralManagerType]):
173
182
  if self._primary_param is not None:
174
183
  self._last_args[self._primary_param] = x
175
184
 
185
+ logger.debug(
186
+ "evaluating rule",
187
+ context={
188
+ "rule": self._func.__qualname__,
189
+ "manager": type(x).__name__,
190
+ },
191
+ )
192
+
176
193
  vals = self._extract_variable_values(x)
177
194
  if self._ignore_if_none and any(v is None for v in vals.values()):
178
195
  self._last_result = None
196
+ logger.debug(
197
+ "skipped rule evaluation due to missing values",
198
+ context={
199
+ "rule": self._func.__qualname__,
200
+ "manager": type(x).__name__,
201
+ "null_variables": [
202
+ name for name, value in vals.items() if value is None
203
+ ],
204
+ },
205
+ )
179
206
  return None
180
207
 
181
208
  self._last_result = self._func(x)
209
+ if self._last_result:
210
+ logger.debug(
211
+ "rule evaluation passed",
212
+ context={
213
+ "rule": self._func.__qualname__,
214
+ "manager": type(x).__name__,
215
+ },
216
+ )
217
+ else:
218
+ logger.info(
219
+ "rule evaluation failed",
220
+ context={
221
+ "rule": self._func.__qualname__,
222
+ "manager": type(x).__name__,
223
+ "variables": self._variables,
224
+ },
225
+ )
182
226
  return self._last_result
183
227
 
184
228
  def validate_custom_error_message(self) -> None:
@@ -214,6 +258,14 @@ class Rule(Generic[GeneralManagerType]):
214
258
  # Validate and substitute template placeholders
215
259
  self.validate_custom_error_message()
216
260
  vals = self._extract_variable_values(self._last_input)
261
+ manager_class = type(self._last_input).__name__
262
+ logger.debug(
263
+ "generating rule error messages",
264
+ context={
265
+ "rule": self._func.__qualname__,
266
+ "manager": manager_class,
267
+ },
268
+ )
217
269
 
218
270
  if self._custom_error_message:
219
271
  formatted = re.sub(
@@ -221,9 +273,34 @@ class Rule(Generic[GeneralManagerType]):
221
273
  lambda m: str(vals.get(m.group(1), m.group(0))),
222
274
  self._custom_error_message,
223
275
  )
276
+ logger.info(
277
+ "rule produced custom error message",
278
+ context={
279
+ "rule": self._func.__qualname__,
280
+ "manager": manager_class,
281
+ "variables": self._variables,
282
+ },
283
+ )
224
284
  return {v: formatted for v in self._variables}
225
285
 
226
286
  errors = self._generate_error_messages(vals)
287
+ if errors:
288
+ logger.info(
289
+ "rule produced error messages",
290
+ context={
291
+ "rule": self._func.__qualname__,
292
+ "manager": manager_class,
293
+ "variables": list(errors.keys()),
294
+ },
295
+ )
296
+ else:
297
+ logger.debug(
298
+ "rule generated no error messages",
299
+ context={
300
+ "rule": self._func.__qualname__,
301
+ "manager": manager_class,
302
+ },
303
+ )
227
304
  return errors or None
228
305
 
229
306
  def _extract_variables(self) -> List[str]:
@@ -355,6 +432,14 @@ class Rule(Generic[GeneralManagerType]):
355
432
  fn = self._get_node_name(left.func)
356
433
  handler = self._handlers.get(fn)
357
434
  if handler:
435
+ logger.debug(
436
+ "rule handler invoked",
437
+ context={
438
+ "rule": self._func.__qualname__,
439
+ "handler": handler.__class__.__name__,
440
+ "function": fn,
441
+ },
442
+ )
358
443
  errors.update(
359
444
  handler.handle(cmp, left, right, op, var_values, self)
360
445
  )
@@ -5,6 +5,8 @@ from __future__ import annotations
5
5
  from importlib import import_module
6
6
  from typing import Any, Iterable, Mapping, MutableMapping, overload
7
7
 
8
+ from general_manager.logging import get_logger
9
+
8
10
 
9
11
  class MissingExportError(AttributeError):
10
12
  """Raised when a requested export is not defined in the public API."""
@@ -24,6 +26,7 @@ class MissingExportError(AttributeError):
24
26
 
25
27
  ModuleTarget = tuple[str, str]
26
28
  ModuleMap = Mapping[str, str | ModuleTarget]
29
+ logger = get_logger("utils.public_api")
27
30
 
28
31
 
29
32
  @overload
@@ -63,11 +66,27 @@ def resolve_export(
63
66
  MissingExportError: If `name` is not present in `module_all`.
64
67
  """
65
68
  if name not in module_all:
69
+ logger.warning(
70
+ "missing public api export",
71
+ context={
72
+ "module": module_globals["__name__"],
73
+ "export": name,
74
+ },
75
+ )
66
76
  raise MissingExportError(module_globals["__name__"], name)
67
77
  module_path, attr_name = _normalize_target(name, module_map[name])
68
78
  module = import_module(module_path)
69
79
  value = getattr(module, attr_name)
70
80
  module_globals[name] = value
81
+ logger.debug(
82
+ "resolved public api export",
83
+ context={
84
+ "module": module_globals["__name__"],
85
+ "export": name,
86
+ "target_module": module_path,
87
+ "target_attribute": attr_name,
88
+ },
89
+ )
71
90
  return value
72
91
 
73
92
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.19.2
3
+ Version: 0.20.1
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: MIT License
@@ -1,13 +1,14 @@
1
1
  general_manager/__init__.py,sha256=Xy4_fFjChIYtlBPDv7K3JEHOulq9_IFXkCc4CElS32Q,1035
2
- general_manager/apps.py,sha256=pY_gR2wMAWw9jyL69dyqtn9NJDeWItp0PCzFEWF_SrE,25852
3
- general_manager/public_api_registry.py,sha256=I6xgSW_02kBPCUoTt03DZdJG_WLQcpy1Caw6F5WEB6g,7756
2
+ general_manager/apps.py,sha256=bz_A2IfgVba2b8lZC5aeQqe40IH7GaavpTEg828Ltm4,27343
3
+ general_manager/logging.py,sha256=bL2dEdNnxo74qRmhOCG06lbPtVCOozfF3GS133T9HH8,4250
4
+ general_manager/public_api_registry.py,sha256=mDpKIE3fmFAMTbQnQdLAZGc_CKNNA6p22Jrql9R6Y4w,7817
4
5
  general_manager/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
6
  general_manager/_types/__init__.py,sha256=RmS0Ok-1-CwWOZL_socLWksEk9MfsshL9eQx879I4mU,60
6
7
  general_manager/_types/api.py,sha256=i5fi7O3C3frI74oqPT-tAoztDplgNDOShyvPNxhw7CY,496
7
8
  general_manager/_types/bucket.py,sha256=DZ3GC-1iR4RiNBKydsMhp_R4GTaYMfsonwe7MCADVP4,435
8
9
  general_manager/_types/cache.py,sha256=jMbIEXDq1pUvVxTN8hvD8rSH7QRjE3ewrMx2gEhYP3w,660
9
10
  general_manager/_types/factory.py,sha256=cPG_td05KCWv2j6_h_vYCKETPol3k_nXkEMWCcUdNHM,1726
10
- general_manager/_types/general_manager.py,sha256=AVCM99Z-YDTvCvbKH8T9Na24-Bnod6JRQEkV9Sdypkg,966
11
+ general_manager/_types/general_manager.py,sha256=Izs47-pOnYJqPmMF7m5DRodSISEztXKSxtBGIHgN8sA,1031
11
12
  general_manager/_types/interface.py,sha256=JlPn3G3ompn1PRfFQfsrIJv2Pf0I3n1RL2ki5_fDX54,605
12
13
  general_manager/_types/manager.py,sha256=rXM6NrQaPdfE9CQoRV_jhbI3SK23rvdpvyBpybVgWi8,506
13
14
  general_manager/_types/measurement.py,sha256=Unkpf3H7TGaUKfkjmFDR7QWBU4lPp5I2A4GlK8pps-Y,443
@@ -15,7 +16,7 @@ general_manager/_types/permission.py,sha256=HJBEOIDYbkYSZkEbT4_6qRDyUk2Ek153K_Rc
15
16
  general_manager/_types/rule.py,sha256=aNbx3jlVinAYQGJlmFwW8rOwTjf19F6khq5xbGTdD3U,238
16
17
  general_manager/_types/utils.py,sha256=8VyD6EKkcRIzdVs6FANP5Ri71eT4BT4c3dTUeyjDr40,1043
17
18
  general_manager/api/__init__.py,sha256=ChV1UPCUjW1Lci0BajmXVtE-3C-WLQTvjO058BMu1Bs,1020
18
- general_manager/api/graphql.py,sha256=khc6d0PHmc8wbnfCG__S3QDejfHDwOWqbFWjClQJmyA,80403
19
+ general_manager/api/graphql.py,sha256=MqNvIWAlHpnRy4WYf6I4bjFLkL29rWWyQls2oS3b1b0,83122
19
20
  general_manager/api/graphql_subscription_consumer.py,sha256=cA-pQNjeF4o92yc2IHtNob6z1CNhHoGxIw2Fgoj24-U,17492
20
21
  general_manager/api/mutation.py,sha256=-zZ_zdyCQW46ihP0kC9BiNGRMPyLYVimxqOKNvP_s48,10155
21
22
  general_manager/api/property.py,sha256=dWRTg8CECSYkIqTBwSbM8CCDEqB_-Zfbtfhxzag7qJI,5690
@@ -25,9 +26,9 @@ general_manager/bucket/calculation_bucket.py,sha256=TpZOJP42CFwsqeQWOrltouClA9Xl
25
26
  general_manager/bucket/database_bucket.py,sha256=Hh__H3E-7tFaUvA5WiKbHmyafyFTzc72HgCvsTgawfU,23008
26
27
  general_manager/bucket/group_bucket.py,sha256=nr2_3rJizOhhbtF5WPiLtZn8lnP2JQ40ehPgYKpwR1M,16369
27
28
  general_manager/cache/__init__.py,sha256=1qLNRTHScsXDoIXKdwvHwyoi7pIb5phv7ASS1AP4Xc8,1014
28
- general_manager/cache/cache_decorator.py,sha256=k3i4tjWJE-XPwyBbebcsvsVeNOyWF6xlsk0MnqwgFdc,3500
29
+ general_manager/cache/cache_decorator.py,sha256=SpXZE89lRqI2jD4iWKbdkvGXp3BBWULvRbG9jM0e4Fs,4203
29
30
  general_manager/cache/cache_tracker.py,sha256=AyDgc_PbxvfE3AJZilKaFCh9Dgg883pMRCXqZxWiILU,2992
30
- general_manager/cache/dependency_index.py,sha256=M9INDjjxROGma7hPh0iecouRS1QoTRLBz9uFl1GRJEk,25600
31
+ general_manager/cache/dependency_index.py,sha256=-1NM13y6OIakw52bvXtWQOz55Mbq4EGq28aXvfpKxO8,26248
31
32
  general_manager/cache/model_dependency_collector.py,sha256=T0g1-0KaEKE8xRNBJj3qsEWKIVlaDZq_MoDn1mCpXv0,2649
32
33
  general_manager/cache/signals.py,sha256=FP_axmdeoJh9ZxjriNgz5zCEQRrVT__KvsHO4eAqdFg,2553
33
34
  general_manager/factory/__init__.py,sha256=A-if6AxDHIejg9S2ObJXGolBfD5xfG9P1aUqT-KEGf0,943
@@ -35,22 +36,22 @@ general_manager/factory/auto_factory.py,sha256=UcX0mxqLyeccuIhjnE8uHYEJ24bMRCZjz
35
36
  general_manager/factory/factories.py,sha256=yVqLSFWuFFTEE9mQGMA9uTRETIruKv0vj6DrUlRoasU,12092
36
37
  general_manager/factory/factory_methods.py,sha256=ZwUQwuLbs1NgVxkjK6idzmWAZY3-9F8wah05bSf14bQ,8407
37
38
  general_manager/interface/__init__.py,sha256=L0IQUHOJehJbX6hzX9nomMhT8f1tqrPtLDgINIpe5-w,1010
38
- general_manager/interface/base_interface.py,sha256=hzfWmjRT5ZMKNaq-0T0Ol05wRSEefhwue5XRP5h1lw0,16183
39
+ general_manager/interface/base_interface.py,sha256=TREetLDX_BAtqrnsvZ9qHUkxl86JCCPzI_eky2bTLwg,16194
39
40
  general_manager/interface/calculation_interface.py,sha256=dsu2pjFgaOv-Kif5YbrsbEvH8Q1n_XfUabPv3CusbtE,5965
40
41
  general_manager/interface/database_based_interface.py,sha256=1L0Q22nEWiO_i--3AtuseAytiXMEkIUF4HL5rTB0s0M,25623
41
- general_manager/interface/database_interface.py,sha256=Xwvhoq17YZeVW8MoKlcJnDc04akdr-NRrDEn_sCTRms,11768
42
+ general_manager/interface/database_interface.py,sha256=ALFQKl7jXNQMHegmUkNKyDGJruMmAmprDiiyYsfZZ_A,11825
42
43
  general_manager/interface/models.py,sha256=MWCgr-Qzauu7jq-15_iEdI0C9B99MsRONV9jUcjkkMU,3699
43
- general_manager/interface/read_only_interface.py,sha256=maZ4xwT_XGCu6aoqkFbdQE_lyXJgCk42BQXmHyrOy7o,14945
44
+ general_manager/interface/read_only_interface.py,sha256=w1XrTeOyf3T7lDfC7ponAMhfNw5LTM46lTOEsocE244,16000
44
45
  general_manager/manager/__init__.py,sha256=Dbka86jtcS2NIxKXA0mohqnLZwLb6NDRX-HeD1_R6UQ,933
45
- general_manager/manager/general_manager.py,sha256=wmmyrM8hNfv5vTGRei4ytpsASQtzJ6zKGo7uEkDv4XA,10231
46
+ general_manager/manager/general_manager.py,sha256=GperYpkoTg_CZlwYBsqGhnaMFENR6jyxanKYdHsvZjg,12083
46
47
  general_manager/manager/group_manager.py,sha256=EhiW2cEnr7J4Ft-FBfuW4hCT5mYg_RCD_-mYF4an9dw,7320
47
48
  general_manager/manager/input.py,sha256=e2M7TSZgNwQz0P1pD_rOpm6-wDUUTjga6kb3nJBR9js,3032
48
- general_manager/manager/meta.py,sha256=RyPwCwVzabz4D6CTVroWkvKQwlx4hAzZfWzbMntkyDk,9646
49
+ general_manager/manager/meta.py,sha256=kkuwKJlbahUMAkh3Gqefbzdm0rnwhD-jbeR2XhveLLs,11391
49
50
  general_manager/measurement/__init__.py,sha256=38-6kTERbw7EeOQAw3eZ9DDEu6hwwqkGJIfJy1D5fx0,993
50
51
  general_manager/measurement/measurement.py,sha256=ArEnntLu3ffHID71uFbXwiB5e5tpsBT2_TbBPJfCWJI,26070
51
52
  general_manager/measurement/measurement_field.py,sha256=zQbyLZT7E9Lx4f3u_wQ-rEoLPqH0FWhfWyOd1BaW--M,13950
52
53
  general_manager/permission/__init__.py,sha256=s4Ka11uYBrymM5O-n5kIxOjwUprZ394jTuzGf5prO_8,981
53
- general_manager/permission/base_permission.py,sha256=XLqtz_rZtS3AXoLG9W5yaSSXD83IZjyeg_bfdqGdzwg,11141
54
+ general_manager/permission/base_permission.py,sha256=IKi5n8t1sKUP_F2eZnzTC8lg7HI8OVo5p1jxCBpyCgw,11961
54
55
  general_manager/permission/file_based_permission.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
55
56
  general_manager/permission/manager_based_permission.py,sha256=OdDGKwutkHTT13bhSeGGycd3xr7wGhuRXsYym3Z9j2A,10613
56
57
  general_manager/permission/mutation_permission.py,sha256=5JV6pluIFPGzJPQ_pr-44zwFg_TgzNwDTHcdpwHettU,4606
@@ -59,7 +60,7 @@ general_manager/permission/permission_data_manager.py,sha256=vNWbPrcw1NUZ-oTRjc3
59
60
  general_manager/permission/utils.py,sha256=yojrcF1kD6KjKugrGyiaf8XOyS_tUA4yB5_RideKJeg,2905
60
61
  general_manager/rule/__init__.py,sha256=dFQLJNr0qpkpuzuBbMY-74jz_Y033YyB9X_OfeJYhSs,1026
61
62
  general_manager/rule/handler.py,sha256=qSBXmXvl7fRgjxUo4wyUOzdZm14a8Umd2Jec4zPXJQc,16309
62
- general_manager/rule/rule.py,sha256=VmaBdV-XmaVYtlDFf8vcmmOsChhLrnSguwlJbQBbvm0,19770
63
+ general_manager/rule/rule.py,sha256=41VXFTSWkBEOj8045vZTezm38VEGimjrk22J4YRl144,22691
63
64
  general_manager/utils/__init__.py,sha256=a72hkiV4_c3wQN-NK-q3Dw25irbzoTTfyKm173WtjwQ,1003
64
65
  general_manager/utils/args_to_kwargs.py,sha256=uvc0YkfeKvny4SGWNVqFioIxajBHrSkzoqrzonu7jeU,2128
65
66
  general_manager/utils/filter_parser.py,sha256=qVkCM5M-gtVrQ3kbHApHjChwSm6Soz60hj41jJdvMvE,5676
@@ -68,10 +69,10 @@ general_manager/utils/json_encoder.py,sha256=0jyjBsZNYGl54hQRkig_5_a20bIN2mV0jlh
68
69
  general_manager/utils/make_cache_key.py,sha256=Uvf7duph8FkqmWWuc4vVdB5Dztur490hPGIFtlkVuT4,1253
69
70
  general_manager/utils/none_to_zero.py,sha256=Z2KVXBKCz02V2ZBs-7tIs_32n7YDxiXyoodW8JbXTDY,667
70
71
  general_manager/utils/path_mapping.py,sha256=f3sd3OFh9aJgyF-ayqr22mHnCo-uoIXqio5DRQmziGM,9931
71
- general_manager/utils/public_api.py,sha256=VvsJWJkJ9HIVu5xSQ_IhX2SROSbORXeGARpGVSGo9r4,2732
72
+ general_manager/utils/public_api.py,sha256=bas4SKchJUg2dI2SLRQwkF_CoXJKKwkzQx_JOjMJ2VY,3272
72
73
  general_manager/utils/testing.py,sha256=_V4Y5SXvu-ocoq-AntPFPd140igclUJUT2xVXxhRrSs,14954
73
- generalmanager-0.19.2.dist-info/licenses/LICENSE,sha256=OcRwUgM4iiESN1oNELgyuwuah39XX-EPZiPDDHndNVI,1070
74
- generalmanager-0.19.2.dist-info/METADATA,sha256=yjpThJqHlO6FdkCiKsddsmI0ZJpT-kXAN69J7gEQj00,8266
75
- generalmanager-0.19.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
76
- generalmanager-0.19.2.dist-info/top_level.txt,sha256=sTDtExP9ga-YP3h3h42yivUY-A2Q23C2nw6LNKOho4I,16
77
- generalmanager-0.19.2.dist-info/RECORD,,
74
+ generalmanager-0.20.1.dist-info/licenses/LICENSE,sha256=OcRwUgM4iiESN1oNELgyuwuah39XX-EPZiPDDHndNVI,1070
75
+ generalmanager-0.20.1.dist-info/METADATA,sha256=aZ08I7nii3gn6zicyZnhavmaZlbQHZIlb8PEaYuT5is,8266
76
+ generalmanager-0.20.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
77
+ generalmanager-0.20.1.dist-info/top_level.txt,sha256=sTDtExP9ga-YP3h3h42yivUY-A2Q23C2nw6LNKOho4I,16
78
+ generalmanager-0.20.1.dist-info/RECORD,,