GeneralManager 0.59.2__tar.gz → 0.59.3__tar.gz

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 (255) hide show
  1. {generalmanager-0.59.2/src/GeneralManager.egg-info → generalmanager-0.59.3}/PKG-INFO +1 -1
  2. {generalmanager-0.59.2 → generalmanager-0.59.3}/pyproject.toml +1 -1
  3. {generalmanager-0.59.2 → generalmanager-0.59.3/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/cache_tracker.py +5 -0
  5. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/dependency_matching.py +6 -0
  6. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/base_interface.py +132 -49
  7. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/core/observability.py +36 -20
  8. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/manager/general_manager.py +12 -10
  9. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/manager/meta.py +16 -4
  10. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/measurement/measurement.py +31 -8
  11. {generalmanager-0.59.2 → generalmanager-0.59.3}/LICENSE +0 -0
  12. {generalmanager-0.59.2 → generalmanager-0.59.3}/README.md +0 -0
  13. {generalmanager-0.59.2 → generalmanager-0.59.3}/setup.cfg +0 -0
  14. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
  15. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  16. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/GeneralManager.egg-info/requires.txt +0 -0
  17. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/GeneralManager.egg-info/top_level.txt +0 -0
  18. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/__init__.py +0 -0
  19. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/__init__.py +0 -0
  20. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/api.py +0 -0
  21. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/bucket.py +0 -0
  22. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/cache.py +0 -0
  23. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/factory.py +0 -0
  24. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/general_manager.py +0 -0
  25. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/interface.py +0 -0
  26. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/manager.py +0 -0
  27. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/measurement.py +0 -0
  28. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/permission.py +0 -0
  29. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/rule.py +0 -0
  30. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/search.py +0 -0
  31. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/_types/utils.py +0 -0
  32. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/__init__.py +0 -0
  33. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql.py +0 -0
  34. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_errors.py +0 -0
  35. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_mutations.py +0 -0
  36. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_prefetch.py +0 -0
  37. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_resolvers.py +0 -0
  38. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_search.py +0 -0
  39. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  40. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_subscriptions.py +0 -0
  41. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_view.py +0 -0
  42. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_warmup.py +0 -0
  43. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_warmup_registry.py +0 -0
  44. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
  45. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/mutation.py +0 -0
  46. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/property.py +0 -0
  47. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/registry.py +0 -0
  48. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/remote_api.py +0 -0
  49. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/remote_invalidation.py +0 -0
  50. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/api/remote_invalidation_client.py +0 -0
  51. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/apps.py +0 -0
  52. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bootstrap.py +0 -0
  53. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/__init__.py +0 -0
  54. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/base_bucket.py +0 -0
  55. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/calculation_bucket.py +0 -0
  56. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/database_bucket.py +0 -0
  57. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/group_bucket.py +0 -0
  58. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/indexing.py +0 -0
  59. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/bucket/request_bucket.py +0 -0
  60. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/__init__.py +0 -0
  61. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/cache_decorator.py +0 -0
  62. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/dependency_cache.py +0 -0
  63. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/dependency_index.py +0 -0
  64. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/dependency_publish.py +0 -0
  65. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/dependency_shards.py +0 -0
  66. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/model_dependency_collector.py +0 -0
  67. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/run_context.py +0 -0
  68. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/cache/signals.py +0 -0
  69. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/__init__.py +0 -0
  70. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/audit.py +0 -0
  71. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/bootstrap.py +0 -0
  72. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/checks.py +0 -0
  73. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/consumer.py +0 -0
  74. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/errors.py +0 -0
  75. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/__init__.py +0 -0
  76. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/__main__.py +0 -0
  77. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/baseline.py +0 -0
  78. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/diagnostics.py +0 -0
  79. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/fingerprints.py +0 -0
  80. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/fixtures.py +0 -0
  81. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/judges/__init__.py +0 -0
  82. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
  83. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/judges/contract.py +0 -0
  84. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
  85. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
  86. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/readiness.py +0 -0
  87. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/runner.py +0 -0
  88. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/evals/traces.py +0 -0
  89. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/grounding.py +0 -0
  90. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/models.py +0 -0
  91. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/__init__.py +0 -0
  92. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/_shared.py +0 -0
  93. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/anthropic.py +0 -0
  94. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/base.py +0 -0
  95. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/google.py +0 -0
  96. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/ollama.py +0 -0
  97. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/providers/openai.py +0 -0
  98. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/rate_limits.py +0 -0
  99. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/routing.py +0 -0
  100. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/schema_index.py +0 -0
  101. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/settings.py +0 -0
  102. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/signals.py +0 -0
  103. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/system_prompt.py +0 -0
  104. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/tool_metadata.py +0 -0
  105. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/tools.py +0 -0
  106. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/chat/views.py +0 -0
  107. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/conf.py +0 -0
  108. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/factory/__init__.py +0 -0
  109. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/factory/auto_factory.py +0 -0
  110. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/factory/factories.py +0 -0
  111. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/factory/factory_methods.py +0 -0
  112. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/__init__.py +0 -0
  113. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/bundles/__init__.py +0 -0
  114. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/bundles/calculation.py +0 -0
  115. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/bundles/database.py +0 -0
  116. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  117. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/bundles/request.py +0 -0
  118. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/__init__.py +0 -0
  119. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/base.py +0 -0
  120. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/builtin.py +0 -0
  121. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  122. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  123. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  124. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/configuration.py +0 -0
  125. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  126. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  127. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  128. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  129. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  130. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/factory.py +0 -0
  131. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  132. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  133. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  134. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  135. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  136. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  137. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  138. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  139. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  140. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  141. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  142. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  143. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
  144. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  145. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  146. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/registry.py +0 -0
  147. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  148. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  149. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  150. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  151. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  152. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/__init__.py +0 -0
  153. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/calculation.py +0 -0
  154. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/database.py +0 -0
  155. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  156. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/read_only.py +0 -0
  157. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  158. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/interfaces/request.py +0 -0
  159. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/manifests/__init__.py +0 -0
  160. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  161. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  162. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/manifests/capability_models.py +0 -0
  163. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/orm_interface.py +0 -0
  164. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/requests.py +0 -0
  165. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/utils/__init__.py +0 -0
  166. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  167. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/utils/errors.py +0 -0
  168. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/interface/utils/models.py +0 -0
  169. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/logging.py +0 -0
  170. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/chat_cleanup.py +0 -0
  171. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/graphql_warmup.py +0 -0
  172. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
  173. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/search_index.py +0 -0
  174. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/search_reconcile.py +0 -0
  175. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  176. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/shell.py +0 -0
  177. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  178. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  179. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/manager/__init__.py +0 -0
  180. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/manager/group_manager.py +0 -0
  181. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/manager/input.py +0 -0
  182. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/measurement/__init__.py +0 -0
  183. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/measurement/measurement_field.py +0 -0
  184. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/metrics/__init__.py +0 -0
  185. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/metrics/graphql.py +0 -0
  186. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0001_initial.py +0 -0
  187. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  188. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  189. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
  190. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0004_search_index_state.py +0 -0
  191. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
  192. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
  193. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/migrations/__init__.py +0 -0
  194. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/models.py +0 -0
  195. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/__init__.py +0 -0
  196. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/audit.py +0 -0
  197. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/base_permission.py +0 -0
  198. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/graphql_capabilities.py +0 -0
  199. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/manager_based_permission.py +0 -0
  200. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/mutation_permission.py +0 -0
  201. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/permission_checks.py +0 -0
  202. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/permission_data_manager.py +0 -0
  203. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/permission/utils.py +0 -0
  204. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/public_api_registry.py +0 -0
  205. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/py.typed +0 -0
  206. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/rule/__init__.py +0 -0
  207. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/rule/handler.py +0 -0
  208. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/rule/rule.py +0 -0
  209. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/__init__.py +0 -0
  210. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/async_tasks.py +0 -0
  211. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backend.py +0 -0
  212. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backend_registry.py +0 -0
  213. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backends/__init__.py +0 -0
  214. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backends/dev.py +0 -0
  215. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backends/meilisearch.py +0 -0
  216. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backends/opensearch.py +0 -0
  217. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/backends/typesense.py +0 -0
  218. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/config.py +0 -0
  219. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/indexer.py +0 -0
  220. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/models.py +0 -0
  221. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/reconciliation.py +0 -0
  222. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/registry.py +0 -0
  223. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/tasks.py +0 -0
  224. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/search/utils.py +0 -0
  225. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/seeding/__init__.py +0 -0
  226. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/seeding/manager_landscape.py +0 -0
  227. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/__init__.py +0 -0
  228. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/args_to_kwargs.py +0 -0
  229. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/filter_parser.py +0 -0
  230. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/format_string.py +0 -0
  231. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/json_encoder.py +0 -0
  232. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/make_cache_key.py +0 -0
  233. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/none_to_zero.py +0 -0
  234. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/path_mapping.py +0 -0
  235. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/public_api.py +0 -0
  236. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/testing.py +0 -0
  237. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/utils/type_checks.py +0 -0
  238. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/__init__.py +0 -0
  239. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/actions.py +0 -0
  240. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/backend_registry.py +0 -0
  241. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/backends/__init__.py +0 -0
  242. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/backends/celery.py +0 -0
  243. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/backends/local.py +0 -0
  244. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/backends/n8n.py +0 -0
  245. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/config.py +0 -0
  246. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/engine.py +0 -0
  247. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/event_registry.py +0 -0
  248. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/events.py +0 -0
  249. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/models.py +0 -0
  250. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/signal_bridge.py +0 -0
  251. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/tasks.py +0 -0
  252. {generalmanager-0.59.2 → generalmanager-0.59.3}/src/general_manager/workflow/telemetry.py +0 -0
  253. {generalmanager-0.59.2 → generalmanager-0.59.3}/tests/test_settings.py +0 -0
  254. {generalmanager-0.59.2 → generalmanager-0.59.3}/tests/test_urls.py +0 -0
  255. {generalmanager-0.59.2 → generalmanager-0.59.3}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.59.2
3
+ Version: 0.59.3
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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GeneralManager"
7
- version = "0.59.2"
7
+ version = "0.59.3"
8
8
  description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
9
9
  readme = "README.md"
10
10
  authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.59.2
3
+ Version: 0.59.3
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
@@ -142,6 +142,11 @@ class DependencyTracker:
142
142
  ]:
143
143
  dep_set.add((class_name, operation, identifier))
144
144
 
145
+ @staticmethod
146
+ def is_active() -> bool:
147
+ """Return whether dependency tracking is active for this execution context."""
148
+ return _dependency_storage.depth >= 0
149
+
145
150
  @staticmethod
146
151
  def reset_thread_local_storage() -> None:
147
152
  """Clear all dependency tracking data for the current thread.
@@ -101,6 +101,12 @@ def normalize_dependency_value(value: object) -> NormalizedDependencyValue:
101
101
 
102
102
  def serialize_normalized_value(value: object) -> str:
103
103
  """Serialize dependency values in the canonical dependency format."""
104
+ if isinstance(value, str):
105
+ return json.dumps(value)
106
+ if value is None or isinstance(value, (int, float, bool)):
107
+ return json.dumps(value)
108
+ if isinstance(value, date):
109
+ return json.dumps(value.isoformat())
104
110
  return json.dumps(normalize_dependency_value(value), sort_keys=True)
105
111
 
106
112
 
@@ -2,7 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
  from abc import ABC
5
+ from collections.abc import Mapping
6
+ from dataclasses import dataclass
5
7
  import inspect
8
+ from types import MappingProxyType
6
9
  from typing import (
7
10
  Type,
8
11
  TYPE_CHECKING,
@@ -190,12 +193,25 @@ def _should_validate_possible_values() -> bool:
190
193
  return bool(settings.DEBUG)
191
194
 
192
195
 
196
+ @dataclass(frozen=True, slots=True)
197
+ class _InputParsingPlan:
198
+ names: tuple[str, ...]
199
+ name_set: frozenset[str]
200
+ alias_to_name: Mapping[str, str]
201
+ required_names: frozenset[str]
202
+ optional_names: frozenset[str]
203
+ dependency_items: tuple[tuple[str, tuple[str, ...]], ...]
204
+ field_state: tuple[tuple[str, int, bool, tuple[str, ...]], ...]
205
+
206
+
193
207
  class InterfaceBase(ABC):
194
208
  """Common base API for interfaces backing GeneralManager classes."""
195
209
 
196
210
  _parent_class: ClassVar[Type["GeneralManager"]]
197
211
  _interface_type: ClassVar[str]
198
212
  input_fields: ClassVar[dict[str, "Input[type[object]]"]]
213
+ _input_parsing_plan: ClassVar[_InputParsingPlan | None] = None
214
+ _input_dependency_order: ClassVar[tuple[str, ...] | None] = None
199
215
  lifecycle_capability_name: ClassVar[CapabilityName | None] = None
200
216
  _capabilities: ClassVar[frozenset[CapabilityName]] = frozenset()
201
217
  _capability_selection: ClassVar["CapabilitySelection | None"] = None
@@ -212,6 +228,8 @@ class InterfaceBase(ABC):
212
228
  This method resets per-subclass capability registries and configuration to a clean default, merges configured capability overrides into the class's capability_overrides mapping, and clears the flag that marks configured capabilities as applied. Keyword arguments are forwarded to the superclass implementation.
213
229
  """
214
230
  super().__init_subclass__(**kwargs)
231
+ cls._input_parsing_plan = None
232
+ cls._input_dependency_order = None
215
233
  cls._capabilities = frozenset()
216
234
  cls._capability_selection = None
217
235
  cls._capability_handlers = {}
@@ -564,6 +582,89 @@ class InterfaceBase(ABC):
564
582
  if callable(hook):
565
583
  register_system_check(cls, hook)
566
584
 
585
+ @classmethod
586
+ def _get_input_parsing_plan(cls) -> _InputParsingPlan:
587
+ plan = cls._input_parsing_plan
588
+ if plan is not None:
589
+ if cls._input_parsing_plan_is_fresh(plan):
590
+ return plan
591
+ cls._input_dependency_order = None
592
+
593
+ names = tuple(cls.input_fields.keys())
594
+ field_items = tuple(cls.input_fields.items())
595
+ name_set = frozenset(names)
596
+ alias_to_name = MappingProxyType({f"{name}_id": name for name in names})
597
+ required_names = frozenset(
598
+ name for name, input_field in field_items if input_field.required
599
+ )
600
+ optional_names = name_set - required_names
601
+ dependency_items = tuple(
602
+ (name, tuple(input_field.depends_on)) for name, input_field in field_items
603
+ )
604
+ field_state = tuple(
605
+ (name, id(input_field), input_field.required, tuple(input_field.depends_on))
606
+ for name, input_field in field_items
607
+ )
608
+
609
+ plan = _InputParsingPlan(
610
+ names=names,
611
+ name_set=name_set,
612
+ alias_to_name=alias_to_name,
613
+ required_names=required_names,
614
+ optional_names=optional_names,
615
+ dependency_items=dependency_items,
616
+ field_state=field_state,
617
+ )
618
+ cls._input_parsing_plan = plan
619
+ return plan
620
+
621
+ @classmethod
622
+ def _input_parsing_plan_is_fresh(cls, plan: _InputParsingPlan) -> bool:
623
+ if len(cls.input_fields) != len(plan.field_state):
624
+ return False
625
+ if tuple(cls.input_fields) != plan.names:
626
+ return False
627
+ for name, input_id, required, depends_on in plan.field_state:
628
+ input_field = cls.input_fields.get(name)
629
+ if input_field is None:
630
+ return False
631
+ if id(input_field) != input_id:
632
+ return False
633
+ if input_field.required != required:
634
+ return False
635
+ if tuple(input_field.depends_on) != depends_on:
636
+ return False
637
+ return True
638
+
639
+ @classmethod
640
+ def _get_input_dependency_order(
641
+ cls,
642
+ plan: _InputParsingPlan,
643
+ ) -> tuple[tuple[str, ...], frozenset[str]]:
644
+ ordered_names = cls._input_dependency_order
645
+ if ordered_names is not None:
646
+ return ordered_names, frozenset()
647
+
648
+ ordered: list[str] = []
649
+ processed: set[str] = set()
650
+ while len(processed) < len(plan.names):
651
+ progress_made = False
652
+ for name, depends_on in plan.dependency_items:
653
+ if name in processed:
654
+ continue
655
+ if all(dependency in processed for dependency in depends_on):
656
+ ordered.append(name)
657
+ processed.add(name)
658
+ progress_made = True
659
+ if not progress_made:
660
+ break
661
+
662
+ ordered_names = tuple(ordered)
663
+ unresolved = frozenset(plan.name_set - processed)
664
+ if not unresolved:
665
+ cls._input_dependency_order = ordered_names
666
+ return ordered_names, unresolved
667
+
567
668
  def parse_input_fields_to_identification(
568
669
  self,
569
670
  *args: object,
@@ -573,10 +674,10 @@ class InterfaceBase(ABC):
573
674
  Convert positional and keyword inputs into a validated identification mapping for the interface's input fields.
574
675
 
575
676
  Positional values are assigned in `input_fields` declaration order before
576
- keyword validation. A keyword named `<field>_id` is accepted only when
577
- `<field>` is a declared input and the canonical field name was not
578
- already supplied. Positional overflow, duplicate positional-plus-keyword
579
- values, alias collisions, and unknown aliases surface as
677
+ keyword validation. A keyword named `<field>_id` is accepted when
678
+ `<field>` is a declared input; if both are supplied, the `_id` alias
679
+ overwrites the canonical value. Positional overflow,
680
+ duplicate positional-plus-keyword values, and unknown aliases surface as
580
681
  `UnexpectedInputArgumentsError` through the argument-normalization path.
581
682
 
582
683
  Parameters:
@@ -596,62 +697,44 @@ class InterfaceBase(ABC):
596
697
  InvalidPossibleValuesTypeError: If an input's `possible_values` configuration is neither callable nor iterable.
597
698
  InvalidInputValueError: If a provided value is not in the allowed set defined by an input's `possible_values`.
598
699
  """
599
- identification: dict[str, object] = {}
600
- kwargs = args_to_kwargs(args, self.input_fields.keys(), kwargs)
601
- # Check for extra arguments
602
- extra_args = set(kwargs.keys()) - set(self.input_fields.keys())
700
+ resolved_identification: dict[str, object] = {}
701
+ plan = type(self)._get_input_parsing_plan()
702
+ kwargs = args_to_kwargs(args, plan.names, kwargs)
703
+
704
+ extra_args = set(kwargs) - plan.name_set
603
705
  if extra_args:
604
706
  handled: set[str] = set()
605
707
  for extra_arg in list(extra_args):
606
- if extra_arg.endswith("_id"):
607
- base = extra_arg[:-3]
608
- if base in self.input_fields:
609
- kwargs[base] = kwargs.pop(extra_arg)
610
- handled.add(extra_arg)
611
- # recompute remaining unknown keys after handling known *_id aliases
612
- remaining = (extra_args - handled) | (
613
- set(kwargs.keys()) - set(self.input_fields.keys())
614
- )
708
+ alias = plan.alias_to_name.get(extra_arg)
709
+ if alias is not None:
710
+ kwargs[alias] = kwargs.pop(extra_arg)
711
+ handled.add(extra_arg)
712
+ remaining = (extra_args - handled) | (set(kwargs) - plan.name_set)
615
713
  if remaining:
616
714
  raise UnexpectedInputArgumentsError(remaining)
617
715
 
618
- for name, input_field in self.input_fields.items():
619
- if name not in kwargs and not input_field.required:
716
+ for name in plan.optional_names:
717
+ if name not in kwargs:
620
718
  kwargs[name] = None
621
719
 
622
- missing_args = {
623
- name
624
- for name, input_field in self.input_fields.items()
625
- if input_field.required and name not in kwargs
626
- }
720
+ missing_args = plan.required_names - set(kwargs)
627
721
  if missing_args:
628
722
  raise MissingInputArgumentsError(missing_args)
629
723
 
630
- # process input fields with dependencies
631
- processed: set[str] = set()
632
- while len(processed) < len(self.input_fields):
633
- progress_made = False
634
- for name, input_field in self.input_fields.items():
635
- if name in processed:
636
- continue
637
- depends_on = input_field.depends_on
638
- if all(dep in processed for dep in depends_on):
639
- cache_context = type(self)._input_possible_values_cache_context(
640
- name
641
- )
642
- value = self.input_fields[name].cast(
643
- kwargs.get(name),
644
- identification,
645
- cache_context=cache_context,
646
- )
647
- self._process_input(name, value, identification)
648
- identification[name] = value
649
- processed.add(name)
650
- progress_made = True
651
- if not progress_made:
652
- # detect circular dependencies
653
- unresolved = set(self.input_fields.keys()) - processed
654
- raise CircularInputDependencyError(unresolved)
724
+ ordered_names, unresolved = type(self)._get_input_dependency_order(plan)
725
+ for name in ordered_names:
726
+ input_field = self.input_fields[name]
727
+ cache_context = type(self)._input_possible_values_cache_context(name)
728
+ value = input_field.cast(
729
+ kwargs.get(name),
730
+ resolved_identification,
731
+ cache_context=cache_context,
732
+ )
733
+ self._process_input(name, value, resolved_identification)
734
+ resolved_identification[name] = value
735
+ if unresolved:
736
+ raise CircularInputDependencyError(unresolved)
737
+ identification = {name: resolved_identification[name] for name in plan.names}
655
738
  return identification
656
739
 
657
740
  @classmethod
@@ -2,6 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import logging
5
6
  from collections.abc import Mapping
6
7
  from typing import ClassVar, Protocol
7
8
 
@@ -54,6 +55,12 @@ class LoggingObservabilityCapability(BaseCapability):
54
55
  """
55
56
  self._logger = get_logger("interface.observability")
56
57
 
58
+ def _debug_enabled(self) -> bool:
59
+ is_enabled_for = getattr(self._logger, "isEnabledFor", None)
60
+ if callable(is_enabled_for):
61
+ return bool(is_enabled_for(logging.DEBUG))
62
+ return True
63
+
57
64
  def before_operation(
58
65
  self,
59
66
  *,
@@ -64,13 +71,14 @@ class LoggingObservabilityCapability(BaseCapability):
64
71
  """
65
72
  Log the start of an interface operation with contextual metadata.
66
73
 
67
- Calls ``self._logger.debug("interface operation start", context=...)``.
68
- The context contains ``operation``, a string ``target`` name,
74
+ When debug logging is enabled, calls
75
+ ``self._logger.debug("interface operation start", context=...)``. The
76
+ context contains ``operation``, a string ``target`` name,
69
77
  ``payload_keys`` sorted from the payload keys, and selected payload
70
78
  metadata values: ``service``, ``method``, ``path``, ``status_code``,
71
- ``retry_count``, and ``request_id``. Selected metadata keys are included
72
- whenever they are present in the payload, including when their value is
73
- ``None``.
79
+ ``retry_count``, and ``request_id``. Selected metadata keys are
80
+ included whenever they are present in the payload, including when their
81
+ value is ``None``.
74
82
 
75
83
  Parameters:
76
84
  operation: Operation name recorded unchanged.
@@ -80,9 +88,13 @@ class LoggingObservabilityCapability(BaseCapability):
80
88
  metadata keys listed above.
81
89
 
82
90
  Raises:
83
- Exception: Target-name lookup, payload-key sorting, payload metadata
84
- lookup, and logger errors propagate unchanged.
91
+ Exception: Logger debug-enabled checks propagate unchanged. When
92
+ debug logging is enabled, target-name lookup, payload-key
93
+ sorting, payload metadata lookup, and logger errors propagate
94
+ unchanged.
85
95
  """
96
+ if not self._debug_enabled():
97
+ return
86
98
  self._logger.debug(
87
99
  "interface operation start",
88
100
  context=self._context(operation, target, payload),
@@ -99,16 +111,16 @@ class LoggingObservabilityCapability(BaseCapability):
99
111
  """
100
112
  Record the end of an interface operation.
101
113
 
102
- Calls ``self._logger.debug("interface operation end", context=...)``.
103
- The context starts with the same fields as ``before_operation()`` and
104
- adds ``result_type`` as ``type(result).__name__``. If
105
- ``result.metadata`` is a mapping, ``status_code``, ``retry_count``, and
106
- ``request_id`` from that ``collections.abc.Mapping`` replace same-named
107
- payload metadata values in the end-event context. Result metadata keys
108
- are included whenever they are present in the mapping, including when
109
- their value is ``None``. A missing ``metadata`` attribute, an
110
- ``AttributeError`` raised while reading ``metadata``, or a non-mapping
111
- metadata value is ignored.
114
+ When debug logging is enabled, calls
115
+ ``self._logger.debug("interface operation end", context=...)``. The
116
+ context starts with the same fields as ``before_operation()`` and adds
117
+ ``result_type`` as ``type(result).__name__``. If ``result.metadata`` is
118
+ a mapping, ``status_code``, ``retry_count``, and ``request_id`` from
119
+ that ``collections.abc.Mapping`` replace same-named payload metadata
120
+ values in the end-event context. Result metadata keys are included
121
+ whenever they are present in the mapping, including when their value is
122
+ ``None``. A missing ``metadata`` attribute, an ``AttributeError`` raised
123
+ while reading ``metadata``, or a non-mapping metadata value is ignored.
112
124
 
113
125
  Parameters:
114
126
  operation: Operation name recorded unchanged.
@@ -119,10 +131,14 @@ class LoggingObservabilityCapability(BaseCapability):
119
131
  metadata are recorded.
120
132
 
121
133
  Raises:
122
- Exception: Target-name lookup, payload-key sorting, payload metadata
123
- lookup, non-``AttributeError`` result metadata lookup failures,
124
- and logger errors propagate unchanged.
134
+ Exception: Logger debug-enabled checks propagate unchanged. When
135
+ debug logging is enabled, target-name lookup, payload-key
136
+ sorting, payload metadata lookup, non-``AttributeError`` result
137
+ metadata lookup failures, and logger errors propagate
138
+ unchanged.
125
139
  """
140
+ if not self._debug_enabled():
141
+ return
126
142
  context = self._context(operation, target, payload)
127
143
  result_metadata = getattr(result, "metadata", None)
128
144
  if isinstance(result_metadata, Mapping):
@@ -75,11 +75,12 @@ class GeneralManager(metaclass=GeneralManagerMeta):
75
75
  self.__id: dict[str, object] = self._interface.identification
76
76
  self._manager_state_valid = True
77
77
  self._manager_state_reason = None
78
- DependencyTracker.track(
79
- self.__class__.__name__,
80
- "identification",
81
- serialize_dependency_identifier(self.__id),
82
- )
78
+ if DependencyTracker.is_active():
79
+ DependencyTracker.track(
80
+ self.__class__.__name__,
81
+ "identification",
82
+ serialize_dependency_identifier(self.__id),
83
+ )
83
84
  logger.debug(
84
85
  "instantiated manager",
85
86
  context={
@@ -127,11 +128,12 @@ class GeneralManager(metaclass=GeneralManagerMeta):
127
128
  manager.__id = manager._interface.identification
128
129
  manager._manager_state_valid = True
129
130
  manager._manager_state_reason = None
130
- DependencyTracker.track(
131
- cls.__name__,
132
- "identification",
133
- serialize_dependency_identifier(manager.__id),
134
- )
131
+ if DependencyTracker.is_active():
132
+ DependencyTracker.track(
133
+ cls.__name__,
134
+ "identification",
135
+ serialize_dependency_identifier(manager.__id),
136
+ )
135
137
  logger.debug(
136
138
  "trusted orm manager hydrated",
137
139
  context={
@@ -127,10 +127,15 @@ class GeneralManagerMeta(type):
127
127
  ``__getattr__`` is only reached for missing names, so inherited
128
128
  ``GeneralManager`` attributes must pass through here to let declared
129
129
  fields override inherited names the same way bootstrap initialization
130
- does. "Non-private" means the requested name does not start with
131
- ``"_"`` and is not exactly ``"Interface"``. Probing an unknown public
132
- name may call ``Interface.get_attributes()``, but it installs
133
- descriptors only when the probed name is declared by the interface.
130
+ does. Once a manager class has completed descriptor initialization,
131
+ attributes already present on that class use normal type lookup without
132
+ rechecking initialization. Missing names and inherited public names
133
+ still pass through initialization so late-discovered fields keep the
134
+ existing override behavior. "Non-private" means the requested name does
135
+ not start with ``"_"`` and is not exactly ``"Interface"``. Probing an
136
+ unknown public name may call ``Interface.get_attributes()``, but it
137
+ installs descriptors only when the probed name is declared by the
138
+ interface.
134
139
 
135
140
  Parameters:
136
141
  attribute_name: Class attribute being read.
@@ -145,6 +150,10 @@ class GeneralManagerMeta(type):
145
150
  ``NotImplementedError`` propagate unchanged.
146
151
  """
147
152
  if not attribute_name.startswith("_") and attribute_name != "Interface":
153
+ class_dict = type.__getattribute__(cls, "__dict__")
154
+ initialized = class_dict.get("_gm_attributes_initialized", False)
155
+ if initialized and attribute_name in class_dict:
156
+ return type.__getattribute__(cls, attribute_name)
148
157
  manager_class = cast(type["GeneralManager"], cls)
149
158
  GeneralManagerMeta.ensure_attributes_initialized(
150
159
  manager_class, attribute_name
@@ -234,6 +243,7 @@ class GeneralManagerMeta(type):
234
243
  GeneralManagerMeta.create_at_properties_for_attributes(
235
244
  attributes.keys(), manager_class
236
245
  )
246
+ type.__setattr__(manager_class, "_gm_attributes_initialized", True)
237
247
  return True
238
248
 
239
249
  try:
@@ -246,6 +256,7 @@ class GeneralManagerMeta(type):
246
256
  GeneralManagerMeta.create_at_properties_for_attributes(
247
257
  attributes.keys(), manager_class
248
258
  )
259
+ type.__setattr__(manager_class, "_gm_attributes_initialized", True)
249
260
  try:
250
261
  GeneralManagerMeta.pending_attribute_initialization.remove(
251
262
  manager_class
@@ -509,6 +520,7 @@ class GeneralManagerMeta(type):
509
520
 
510
521
  for attr_name in attributes:
511
522
  setattr(new_class, attr_name, descriptor_method(attr_name, new_class))
523
+ type.__setattr__(new_class, "_gm_attributes_initialized", True)
512
524
 
513
525
 
514
526
  _CAPABILITY_BUILDER: "ManifestCapabilityBuilder | None" = None
@@ -3,6 +3,7 @@
3
3
  # units.py
4
4
  from __future__ import annotations
5
5
  from collections.abc import Callable
6
+ from functools import lru_cache
6
7
  from typing import TypeAlias, TypeGuard, cast
7
8
  import pint
8
9
  from decimal import Decimal, getcontext, InvalidOperation
@@ -63,21 +64,43 @@ def _is_numeric_scalar(value: object) -> TypeGuard[NumericScalar]:
63
64
  return not isinstance(value, bool) and isinstance(value, (Decimal, float, int))
64
65
 
65
66
 
66
- def _unit_uses_offset(unit: str | pint.Unit | MeasurementQuantity) -> bool:
67
- """Return whether a Pint unit has offset conversion semantics."""
67
+ @lru_cache(maxsize=256)
68
+ def _unit_uses_offset_for_unit_string(unit: str) -> bool:
69
+ """Return whether a unit string has offset conversion semantics."""
68
70
 
69
- parsed_unit = ureg.parse_units(
70
- str(unit.units if isinstance(unit, PlainQuantity) else unit)
71
- )
72
- for unit_name, power in parsed_unit._units.items():
71
+ for unit_name, power in _pint_unit_components(unit):
73
72
  if power != 1:
74
73
  continue
75
- converter = ureg._units[unit_name].converter
76
- if getattr(converter, "offset", None) is not None:
74
+ if _pint_unit_component_uses_offset(unit_name):
77
75
  return True
78
76
  return False
79
77
 
80
78
 
79
+ def _pint_unit_components(unit: str) -> tuple[tuple[str, object], ...]:
80
+ """Return Pint unit component names and powers for one unit expression."""
81
+
82
+ parsed_unit = ureg.parse_units(unit)
83
+ return tuple(parsed_unit._units.items())
84
+
85
+
86
+ def _pint_unit_component_uses_offset(unit_name: str) -> bool:
87
+ """Return whether a Pint unit component has offset conversion semantics."""
88
+
89
+ converter = ureg._units[unit_name].converter
90
+ return getattr(converter, "offset", None) is not None
91
+
92
+
93
+ def _unit_uses_offset(unit: str | pint.Unit | MeasurementQuantity) -> bool:
94
+ """Return whether a Pint unit has offset conversion semantics."""
95
+
96
+ unit_string = str(unit.units if isinstance(unit, PlainQuantity) else unit)
97
+ return _unit_uses_offset_for_unit_string(unit_string)
98
+
99
+
100
+ _unit_uses_offset.cache_clear = _unit_uses_offset_for_unit_string.cache_clear # type: ignore[attr-defined]
101
+ _unit_uses_offset.cache_info = _unit_uses_offset_for_unit_string.cache_info # type: ignore[attr-defined]
102
+
103
+
81
104
  def _quantity_as_float(quantity: MeasurementQuantity) -> PlainQuantity[float]:
82
105
  """Rebuild a quantity with a float magnitude so offset-unit math stays in Pint."""
83
106
 
File without changes