GeneralManager 0.80.1__tar.gz → 0.80.2__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 (335) hide show
  1. {generalmanager-0.80.1/src/GeneralManager.egg-info → generalmanager-0.80.2}/PKG-INFO +1 -1
  2. {generalmanager-0.80.1 → generalmanager-0.80.2}/pyproject.toml +1 -1
  3. {generalmanager-0.80.1 → generalmanager-0.80.2/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/GeneralManager.egg-info/SOURCES.txt +1 -0
  5. generalmanager-0.80.2/src/general_manager/cache/_dependency_graph.py +116 -0
  6. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/cache_decorator.py +37 -11
  7. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/cache_tracker.py +165 -30
  8. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/dependency_cache.py +37 -2
  9. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/model_dependency_collector.py +13 -9
  10. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/run_context.py +38 -14
  11. generalmanager-0.80.2/src/general_manager/cache/run_context_lru.py +3307 -0
  12. generalmanager-0.80.1/src/general_manager/cache/run_context_lru.py +0 -1389
  13. {generalmanager-0.80.1 → generalmanager-0.80.2}/LICENSE +0 -0
  14. {generalmanager-0.80.1 → generalmanager-0.80.2}/README.md +0 -0
  15. {generalmanager-0.80.1 → generalmanager-0.80.2}/setup.cfg +0 -0
  16. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  17. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/GeneralManager.egg-info/requires.txt +0 -0
  18. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/GeneralManager.egg-info/top_level.txt +0 -0
  19. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/__init__.py +0 -0
  20. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/__init__.py +0 -0
  21. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/api.py +0 -0
  22. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/bucket.py +0 -0
  23. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/cache.py +0 -0
  24. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/dataframes.py +0 -0
  25. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/factory.py +0 -0
  26. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/general_manager.py +0 -0
  27. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/interface.py +0 -0
  28. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/manager.py +0 -0
  29. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/measurement.py +0 -0
  30. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/permission.py +0 -0
  31. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/rule.py +0 -0
  32. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/search.py +0 -0
  33. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/_types/utils.py +0 -0
  34. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/__init__.py +0 -0
  35. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql.py +0 -0
  36. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_as_of.py +0 -0
  37. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_errors.py +0 -0
  38. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_groups.py +0 -0
  39. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_mutations.py +0 -0
  40. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_ordering.py +0 -0
  41. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_output.py +0 -0
  42. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_prefetch.py +0 -0
  43. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_relations.py +0 -0
  44. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_resolvers.py +0 -0
  45. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_search.py +0 -0
  46. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  47. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_subscriptions.py +0 -0
  48. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_type.py +0 -0
  49. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_view.py +0 -0
  50. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_warmup.py +0 -0
  51. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_warmup_registry.py +0 -0
  52. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
  53. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/mutation.py +0 -0
  54. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/notification_batching.py +0 -0
  55. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/property.py +0 -0
  56. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/registry.py +0 -0
  57. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/remote_api.py +0 -0
  58. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/remote_invalidation.py +0 -0
  59. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/api/remote_invalidation_client.py +0 -0
  60. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/apps.py +0 -0
  61. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/as_of.py +0 -0
  62. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bootstrap.py +0 -0
  63. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/__init__.py +0 -0
  64. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/_materialized_bucket.py +0 -0
  65. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/_ordering.py +0 -0
  66. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/base_bucket.py +0 -0
  67. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/calculation_bucket.py +0 -0
  68. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/database_bucket.py +0 -0
  69. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/excel_bucket.py +0 -0
  70. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/group_bucket.py +0 -0
  71. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/indexing.py +0 -0
  72. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/projection.py +0 -0
  73. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/bucket/request_bucket.py +0 -0
  74. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/__init__.py +0 -0
  75. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/data_change_context.py +0 -0
  76. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/dependency_index.py +0 -0
  77. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/dependency_matching.py +0 -0
  78. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/dependency_publish.py +0 -0
  79. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/dependency_shards.py +0 -0
  80. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/cache/signals.py +0 -0
  81. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/__init__.py +0 -0
  82. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/audit.py +0 -0
  83. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/bootstrap.py +0 -0
  84. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/checks.py +0 -0
  85. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/consumer.py +0 -0
  86. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/context.py +0 -0
  87. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/errors.py +0 -0
  88. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/__init__.py +0 -0
  89. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/__main__.py +0 -0
  90. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/baseline.py +0 -0
  91. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
  92. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
  93. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
  94. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
  95. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
  96. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
  97. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
  98. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/diagnostics.py +0 -0
  99. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/fingerprints.py +0 -0
  100. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/fixtures.py +0 -0
  101. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/judges/__init__.py +0 -0
  102. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
  103. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/judges/contract.py +0 -0
  104. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
  105. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
  106. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/readiness.py +0 -0
  107. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/runner.py +0 -0
  108. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/evals/traces.py +0 -0
  109. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/grounding.py +0 -0
  110. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/models.py +0 -0
  111. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/__init__.py +0 -0
  112. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/budget.py +0 -0
  113. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/calculations.py +0 -0
  114. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/catalog.py +0 -0
  115. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/config.py +0 -0
  116. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/events.py +0 -0
  117. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/evidence.py +0 -0
  118. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/models.py +0 -0
  119. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/planner.py +0 -0
  120. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/provider_calls.py +0 -0
  121. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/resolver.py +0 -0
  122. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/routing.py +0 -0
  123. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/scheduler.py +0 -0
  124. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/synthesis.py +0 -0
  125. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/planned/validation.py +0 -0
  126. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/__init__.py +0 -0
  127. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/_shared.py +0 -0
  128. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/anthropic.py +0 -0
  129. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/base.py +0 -0
  130. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/google.py +0 -0
  131. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/ollama.py +0 -0
  132. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/providers/openai.py +0 -0
  133. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/rate_limits.py +0 -0
  134. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/routing.py +0 -0
  135. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/schema_index.py +0 -0
  136. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/settings.py +0 -0
  137. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/signals.py +0 -0
  138. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/system_prompt.py +0 -0
  139. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/tool_metadata.py +0 -0
  140. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/tools.py +0 -0
  141. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/turns.py +0 -0
  142. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/chat/views.py +0 -0
  143. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/conf.py +0 -0
  144. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/dataframes/__init__.py +0 -0
  145. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/dataframes/measurements.py +0 -0
  146. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/factory/__init__.py +0 -0
  147. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/factory/auto_factory.py +0 -0
  148. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/factory/factories.py +0 -0
  149. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/factory/factory_methods.py +0 -0
  150. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/__init__.py +0 -0
  151. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/base_interface.py +0 -0
  152. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/bundles/__init__.py +0 -0
  153. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/bundles/calculation.py +0 -0
  154. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/bundles/database.py +0 -0
  155. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/bundles/excel.py +0 -0
  156. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  157. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/bundles/request.py +0 -0
  158. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/__init__.py +0 -0
  159. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/base.py +0 -0
  160. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/builtin.py +0 -0
  161. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  162. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  163. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
  164. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  165. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/configuration.py +0 -0
  166. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  167. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  168. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
  169. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  170. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  171. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  172. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  173. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/factory.py +0 -0
  174. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  175. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  176. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  177. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  178. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  179. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  180. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  181. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  182. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  183. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  184. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
  185. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  186. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  187. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
  188. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  189. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  190. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/registry.py +0 -0
  191. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  192. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  193. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/excel.py +0 -0
  194. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/excel_store.py +0 -0
  195. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/excel_workbook.py +0 -0
  196. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  197. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  198. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  199. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/__init__.py +0 -0
  200. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/calculation.py +0 -0
  201. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/database.py +0 -0
  202. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/excel.py +0 -0
  203. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  204. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/read_only.py +0 -0
  205. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  206. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/interfaces/request.py +0 -0
  207. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/manifests/__init__.py +0 -0
  208. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  209. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  210. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/manifests/capability_models.py +0 -0
  211. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/orm_interface.py +0 -0
  212. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/requests.py +0 -0
  213. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/utils/__init__.py +0 -0
  214. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  215. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/utils/errors.py +0 -0
  216. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/utils/history.py +0 -0
  217. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/interface/utils/models.py +0 -0
  218. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/logging.py +0 -0
  219. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/chat_cleanup.py +0 -0
  220. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
  221. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/graphql_warmup.py +0 -0
  222. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
  223. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/search_index.py +0 -0
  224. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/search_reconcile.py +0 -0
  225. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  226. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/shell.py +0 -0
  227. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  228. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  229. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/manager/__init__.py +0 -0
  230. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/manager/general_manager.py +0 -0
  231. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/manager/group_manager.py +0 -0
  232. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/manager/input.py +0 -0
  233. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/manager/meta.py +0 -0
  234. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/measurement/__init__.py +0 -0
  235. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/measurement/measurement.py +0 -0
  236. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/measurement/measurement_field.py +0 -0
  237. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/metrics/__init__.py +0 -0
  238. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/metrics/graphql.py +0 -0
  239. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0001_initial.py +0 -0
  240. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  241. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  242. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
  243. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0004_search_index_state.py +0 -0
  244. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
  245. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
  246. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0007_upload_intent.py +0 -0
  247. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
  248. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
  249. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
  250. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
  251. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
  252. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/migrations/__init__.py +0 -0
  253. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/models.py +0 -0
  254. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/__init__.py +0 -0
  255. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/audit.py +0 -0
  256. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/base_permission.py +0 -0
  257. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/graphql_capabilities.py +0 -0
  258. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/manager_based_permission.py +0 -0
  259. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/mutation_permission.py +0 -0
  260. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/permission_checks.py +0 -0
  261. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/permission_data_manager.py +0 -0
  262. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/permission/utils.py +0 -0
  263. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/public_api_registry.py +0 -0
  264. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/py.typed +0 -0
  265. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/rule/__init__.py +0 -0
  266. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/rule/handler.py +0 -0
  267. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/rule/rule.py +0 -0
  268. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/__init__.py +0 -0
  269. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/async_tasks.py +0 -0
  270. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backend.py +0 -0
  271. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backend_registry.py +0 -0
  272. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backends/__init__.py +0 -0
  273. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backends/dev.py +0 -0
  274. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backends/meilisearch.py +0 -0
  275. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backends/opensearch.py +0 -0
  276. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/backends/typesense.py +0 -0
  277. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/checks.py +0 -0
  278. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/config.py +0 -0
  279. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/indexer.py +0 -0
  280. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/invalidation.py +0 -0
  281. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/m2m_invalidation.py +0 -0
  282. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/models.py +0 -0
  283. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/reconciliation.py +0 -0
  284. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/registry.py +0 -0
  285. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/tasks.py +0 -0
  286. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/search/utils.py +0 -0
  287. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/seeding/__init__.py +0 -0
  288. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/seeding/manager_landscape.py +0 -0
  289. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/__init__.py +0 -0
  290. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/adapters.py +0 -0
  291. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/checks.py +0 -0
  292. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/config.py +0 -0
  293. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/errors.py +0 -0
  294. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/finalization.py +0 -0
  295. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/graphql.py +0 -0
  296. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/graphql_types.py +0 -0
  297. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/metrics.py +0 -0
  298. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/models.py +0 -0
  299. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/public.py +0 -0
  300. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/s3.py +0 -0
  301. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/services.py +0 -0
  302. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/tokens.py +0 -0
  303. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/types.py +0 -0
  304. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/urls.py +0 -0
  305. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/uploads/views.py +0 -0
  306. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/__init__.py +0 -0
  307. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/_args_to_kwargs.py +0 -0
  308. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/_cache_key_encoder.py +0 -0
  309. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/_make_cache_key.py +0 -0
  310. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/_none_to_zero.py +0 -0
  311. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/filter_parser.py +0 -0
  312. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/format_string.py +0 -0
  313. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/json_encoder.py +0 -0
  314. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/path_mapping.py +0 -0
  315. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/public_api.py +0 -0
  316. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/testing.py +0 -0
  317. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/utils/type_checks.py +0 -0
  318. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/__init__.py +0 -0
  319. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/actions.py +0 -0
  320. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/backend_registry.py +0 -0
  321. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/backends/__init__.py +0 -0
  322. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/backends/celery.py +0 -0
  323. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/backends/local.py +0 -0
  324. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/backends/n8n.py +0 -0
  325. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/config.py +0 -0
  326. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/engine.py +0 -0
  327. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/event_registry.py +0 -0
  328. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/events.py +0 -0
  329. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/models.py +0 -0
  330. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/signal_bridge.py +0 -0
  331. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/tasks.py +0 -0
  332. {generalmanager-0.80.1 → generalmanager-0.80.2}/src/general_manager/workflow/telemetry.py +0 -0
  333. {generalmanager-0.80.1 → generalmanager-0.80.2}/tests/test_settings.py +0 -0
  334. {generalmanager-0.80.1 → generalmanager-0.80.2}/tests/test_urls.py +0 -0
  335. {generalmanager-0.80.1 → generalmanager-0.80.2}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.80.1
3
+ Version: 0.80.2
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.80.1"
7
+ version = "0.80.2"
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.80.1
3
+ Version: 0.80.2
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
@@ -67,6 +67,7 @@ src/general_manager/bucket/indexing.py
67
67
  src/general_manager/bucket/projection.py
68
68
  src/general_manager/bucket/request_bucket.py
69
69
  src/general_manager/cache/__init__.py
70
+ src/general_manager/cache/_dependency_graph.py
70
71
  src/general_manager/cache/cache_decorator.py
71
72
  src/general_manager/cache/cache_tracker.py
72
73
  src/general_manager/cache/data_change_context.py
@@ -0,0 +1,116 @@
1
+ """Private immutable dependency snapshots shared by cache computations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
6
+ from dataclasses import dataclass
7
+ from typing import cast
8
+
9
+ from general_manager.cache.dependency_index import Dependency
10
+
11
+
12
+ @dataclass(frozen=True, slots=True, eq=False)
13
+ class _DependencyBlock:
14
+ """One immutable collection of directly observed dependency tuples.
15
+
16
+ Equality deliberately remains identity based. A block can be referenced by
17
+ several snapshot leaves (notably prefetched dependency-cache hits), and a
18
+ materialization must visit that shared block only once.
19
+ """
20
+
21
+ dependencies: tuple[Dependency, ...] | frozenset[Dependency]
22
+
23
+
24
+ @dataclass(frozen=True, slots=True, eq=False)
25
+ class DependencySnapshot:
26
+ """An immutable node containing direct dependencies and child snapshots."""
27
+
28
+ block: _DependencyBlock | None
29
+ children: tuple["DependencySnapshot", ...]
30
+
31
+
32
+ _EMPTY_SNAPSHOT = DependencySnapshot(block=None, children=())
33
+
34
+
35
+ def empty_dependency_snapshot() -> DependencySnapshot:
36
+ """Return the shared empty dependency root."""
37
+ return _EMPTY_SNAPSHOT
38
+
39
+
40
+ def snapshot_from_dependencies(
41
+ dependencies: Iterable[Dependency],
42
+ ) -> DependencySnapshot:
43
+ """Freeze direct dependencies at a boundary into a standalone leaf."""
44
+ # Hits already own an immutable dependency container. Retaining that
45
+ # container by identity is what lets independent leaf wrappers share its
46
+ # storage (and lets materialization/accounting charge it once). Mutable
47
+ # inputs must still be copied at this boundary.
48
+ if type(dependencies) in (tuple, frozenset):
49
+ frozen_dependencies = cast(
50
+ tuple[Dependency, ...] | frozenset[Dependency], dependencies
51
+ )
52
+ else:
53
+ frozen_dependencies = tuple(dependencies)
54
+ if not frozen_dependencies:
55
+ return _EMPTY_SNAPSHOT
56
+ return DependencySnapshot(_DependencyBlock(frozen_dependencies), ())
57
+
58
+
59
+ class DependencyCapture:
60
+ """Mutable builder used only while one cache calculation is executing."""
61
+
62
+ __slots__ = ("_child_ids", "_children", "_dependencies")
63
+
64
+ def __init__(self) -> None:
65
+ """Start an empty per-calculation builder."""
66
+ self._dependencies: set[Dependency] = set()
67
+ self._children: list[DependencySnapshot] = []
68
+ self._child_ids: set[int] = set()
69
+
70
+ def add(self, dependency: Dependency) -> None:
71
+ """Record one direct dependency in this calculation frame."""
72
+ self._dependencies.add(dependency)
73
+
74
+ def attach(self, snapshot: DependencySnapshot) -> None:
75
+ """Attach a child snapshot once, using node identity for deduplication."""
76
+ if snapshot is _EMPTY_SNAPSHOT:
77
+ return
78
+ snapshot_id = id(snapshot)
79
+ if snapshot_id not in self._child_ids:
80
+ self._child_ids.add(snapshot_id)
81
+ self._children.append(snapshot)
82
+
83
+ def freeze(self) -> DependencySnapshot:
84
+ """Build the immutable root, reusing simple child-only snapshots."""
85
+ if not self._dependencies:
86
+ if not self._children:
87
+ return _EMPTY_SNAPSHOT
88
+ if len(self._children) == 1:
89
+ return self._children[0]
90
+ return DependencySnapshot(None, tuple(self._children))
91
+ return DependencySnapshot(
92
+ _DependencyBlock(tuple(self._dependencies)),
93
+ tuple(self._children),
94
+ )
95
+
96
+
97
+ def materialize_dependencies(snapshot: DependencySnapshot) -> set[Dependency]:
98
+ """Iteratively flatten a graph, visiting nodes and direct blocks by identity."""
99
+ dependencies: set[Dependency] = set()
100
+ pending = [snapshot]
101
+ seen_nodes: set[int] = set()
102
+ seen_dependency_containers: set[int] = set()
103
+ while pending:
104
+ node = pending.pop()
105
+ node_id = id(node)
106
+ if node_id in seen_nodes:
107
+ continue
108
+ seen_nodes.add(node_id)
109
+ block = node.block
110
+ if block is not None:
111
+ dependency_container_id = id(block.dependencies)
112
+ if dependency_container_id not in seen_dependency_containers:
113
+ seen_dependency_containers.add(dependency_container_id)
114
+ dependencies.update(block.dependencies)
115
+ pending.extend(node.children)
116
+ return dependencies
@@ -1,6 +1,6 @@
1
1
  """Helpers for caching GeneralManager computations with dependency tracking."""
2
2
 
3
- from collections.abc import Callable, Iterable
3
+ from collections.abc import Callable, Iterable, Mapping
4
4
  from functools import partial, wraps
5
5
  from hashlib import sha256
6
6
  import inspect
@@ -8,7 +8,10 @@ from typing import Literal, ParamSpec, Protocol, TypeVar, cast, overload
8
8
 
9
9
  from django.core.cache import cache as django_cache
10
10
 
11
- from general_manager.cache.cache_tracker import DependencyTracker
11
+ from general_manager.cache.cache_tracker import (
12
+ DependencyTracker,
13
+ _DependencyCaptureScope,
14
+ )
12
15
  from general_manager.cache.dependency_cache import (
13
16
  DependencyCacheHit,
14
17
  dependency_cache_prefetch_bundle_key,
@@ -170,7 +173,26 @@ def _reject_awaitable_cache_result(result: object) -> None:
170
173
 
171
174
  def _replay_run_cache_entry_dependencies(entry: _RunCacheEntry) -> None:
172
175
  """Replay a decorated run-cache entry into every active dependency tracker."""
173
- for class_name, operation, identifier in entry.dependencies:
176
+ DependencyTracker._attach_snapshot(entry.dependency_root)
177
+
178
+
179
+ def _track_model_arguments(
180
+ args: tuple[object, ...],
181
+ kwargs: Mapping[str, object],
182
+ capture: _DependencyCaptureScope,
183
+ ) -> None:
184
+ """Track model argument dependencies as they are discovered.
185
+
186
+ Collector iteration can raise while serializing a later argument. Recording
187
+ each earlier value immediately preserves the same partial-dependency
188
+ behavior as ordinary source reads.
189
+ """
190
+ for class_name, operation, identifier in ModelDependencyCollector._iter_args(
191
+ args, kwargs
192
+ ):
193
+ dependency = (class_name, operation, identifier)
194
+ if capture._record_argument_dependency(dependency):
195
+ continue
174
196
  DependencyTracker._track_validated(class_name, operation, identifier)
175
197
 
176
198
 
@@ -418,15 +440,16 @@ def cached(
418
440
  _replay_run_cache_entry_dependencies(cached_run_value)
419
441
  return cast(R, cached_run_value.value)
420
442
  return cast(R, cached_run_value)
421
- with DependencyTracker() as dependencies:
443
+ with DependencyTracker._capture() as capture:
422
444
  result = decorated_func(*args, **kwargs)
423
- ModelDependencyCollector.add_args(dependencies, args, kwargs)
445
+ _track_model_arguments(args, kwargs, capture)
424
446
  _reject_awaitable_cache_result(result)
447
+ assert capture.snapshot is not None
425
448
  active_context.set(
426
449
  key,
427
450
  _RunCacheEntry(
428
451
  value=result,
429
- dependencies=frozenset(dependencies),
452
+ dependency_root=capture.snapshot,
430
453
  ),
431
454
  )
432
455
  return result
@@ -437,15 +460,16 @@ def cached(
437
460
  _replay_run_cache_entry_dependencies(cached_run_value)
438
461
  return cast(R, cached_run_value.value)
439
462
  return cast(R, cached_run_value)
440
- with DependencyTracker() as dependencies:
463
+ with DependencyTracker._capture() as capture:
441
464
  result = decorated_func(*args, **kwargs)
442
- ModelDependencyCollector.add_args(dependencies, args, kwargs)
465
+ _track_model_arguments(args, kwargs, capture)
443
466
  _reject_awaitable_cache_result(result)
467
+ assert capture.snapshot is not None
444
468
  context.set(
445
469
  key,
446
470
  _RunCacheEntry(
447
471
  value=result,
448
- dependencies=frozenset(dependencies),
472
+ dependency_root=capture.snapshot,
449
473
  ),
450
474
  )
451
475
  return result
@@ -566,10 +590,12 @@ def cached(
566
590
  return return_cached_hit(cached_hit, "cache hit")
567
591
 
568
592
  started_generation = get_dependency_generation()
569
- with DependencyTracker() as dependencies:
593
+ with DependencyTracker._capture() as capture:
570
594
  result = decorated_func(*args, **kwargs)
571
- ModelDependencyCollector.add_args(dependencies, args, kwargs)
595
+ _track_model_arguments(args, kwargs, capture)
572
596
  _reject_awaitable_cache_result(result)
597
+ assert capture.snapshot is not None
598
+ dependencies = DependencyTracker._materialize_snapshot(capture.snapshot)
573
599
 
574
600
  def record_many(
575
601
  entries: Iterable[tuple[str, Iterable[Dependency]]],
@@ -1,6 +1,8 @@
1
1
  """Context manager utilities for tracking cache dependencies per thread."""
2
2
 
3
- from collections.abc import Collection, Iterable
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable
4
6
  import threading
5
7
  from types import TracebackType
6
8
 
@@ -9,6 +11,12 @@ from general_manager.cache.dependency_index import (
9
11
  filter_type,
10
12
  general_manager_name,
11
13
  )
14
+ from general_manager.cache._dependency_graph import (
15
+ DependencyCapture,
16
+ DependencySnapshot,
17
+ materialize_dependencies,
18
+ snapshot_from_dependencies,
19
+ )
12
20
 
13
21
  _SUPPORTED_OPERATIONS: frozenset[filter_type] = frozenset(
14
22
  {"filter", "exclude", "identification", "request_query", "all"}
@@ -35,13 +43,18 @@ class _TrackedDependencySet(set[Dependency]):
35
43
  """Dependency set returned by DependencyTracker for framework-captured deps."""
36
44
 
37
45
 
46
+ class _CapturedDependencySet(_TrackedDependencySet):
47
+ """Private materialization of a trusted immutable dependency graph."""
48
+
49
+
38
50
  class _DependencyStorage(threading.local):
39
51
  """Thread-local dependency tracking stack."""
40
52
 
41
53
  def __init__(self) -> None:
42
54
  """Initialize an inactive dependency stack for one thread."""
43
55
  self.dependencies: list[_TrackedDependencySet] = []
44
- self.depth = -1
56
+ self.captures: list[DependencyCapture] = []
57
+ self.generation = 0
45
58
  self.stack_version = 0
46
59
  self.last_dependency: Dependency | None = None
47
60
  self.last_dependency_stack_version = -1
@@ -50,8 +63,12 @@ class _DependencyStorage(threading.local):
50
63
 
51
64
  def reset(self) -> None:
52
65
  """Clear all active dependency scopes for the current thread."""
66
+ # Capture scopes retain direct references to their old parent builders.
67
+ # Detaching this stack therefore prevents later ordinary reads from
68
+ # reaching it while still allowing each scope to finalize its own result.
53
69
  self.dependencies.clear()
54
- self.depth = -1
70
+ self.captures.clear()
71
+ self.generation += 1
55
72
  self.stack_version += 1
56
73
  self.last_dependency = None
57
74
  self.last_dependency_stack_version = -1
@@ -62,6 +79,79 @@ class _DependencyStorage(threading.local):
62
79
  _dependency_storage = _DependencyStorage()
63
80
 
64
81
 
82
+ def _clear_duplicate_state(storage: _DependencyStorage) -> None:
83
+ """Release duplicate-suppression references after the final scope exits."""
84
+ storage.last_dependency = None
85
+ storage.last_dependency_stack_version = -1
86
+ storage.seen_dependencies.clear()
87
+ storage.seen_dependencies_stack_version = -1
88
+
89
+
90
+ class _DependencyCaptureScope:
91
+ """Private compact dependency capture for one decorated computation."""
92
+
93
+ def __init__(self) -> None:
94
+ """Create an unentered capture scope."""
95
+ self._capture: DependencyCapture | None = None
96
+ self._parent_capture: DependencyCapture | None = None
97
+ self._generation = -1
98
+ self.snapshot: DependencySnapshot | None = None
99
+
100
+ def __enter__(self) -> "_DependencyCaptureScope":
101
+ storage = _dependency_storage
102
+ self._generation = storage.generation
103
+ self.snapshot = None
104
+ capture = DependencyCapture()
105
+ self._capture = capture
106
+ self._parent_capture = storage.captures[-1] if storage.captures else None
107
+ storage.captures.append(capture)
108
+ storage.stack_version += 1
109
+ return self
110
+
111
+ def __exit__(
112
+ self,
113
+ exc_type: type[BaseException] | None,
114
+ exc_val: BaseException | None,
115
+ exc_tb: TracebackType | None,
116
+ ) -> None:
117
+ del exc_type, exc_val, exc_tb
118
+ storage = _dependency_storage
119
+ capture = self._capture
120
+ if capture is None:
121
+ return
122
+ parent_capture = self._parent_capture
123
+ self._capture = None
124
+ self._parent_capture = None
125
+ snapshot = capture.freeze()
126
+ self.snapshot = snapshot
127
+ if (
128
+ storage.generation == self._generation
129
+ and storage.captures
130
+ and storage.captures[-1] is capture
131
+ ):
132
+ storage.captures.pop()
133
+ storage.stack_version += 1
134
+ storage.last_dependency = None
135
+ storage.last_dependency_stack_version = -1
136
+ if not storage.dependencies and not storage.captures:
137
+ _clear_duplicate_state(storage)
138
+ if parent_capture is not None:
139
+ parent_capture.attach(snapshot)
140
+
141
+ def _record_argument_dependency(self, dependency: Dependency) -> bool:
142
+ """Record a decorator-derived argument after this scope was detached."""
143
+ capture = self._capture
144
+ storage = _dependency_storage
145
+ if capture is not None and (
146
+ storage.generation != self._generation
147
+ or not storage.captures
148
+ or storage.captures[-1] is not capture
149
+ ):
150
+ capture.add(dependency)
151
+ return True
152
+ return False
153
+
154
+
65
155
  class DependencyTracker:
66
156
  """Capture dependencies touched inside a read or cache-computation scope.
67
157
 
@@ -69,6 +159,10 @@ class DependencyTracker:
69
159
  tracker state if their execution is interleaved inside one active context.
70
160
  """
71
161
 
162
+ def __init__(self) -> None:
163
+ """Create per-thread scope storage before the tracker can be shared."""
164
+ self._scope_storage = threading.local()
165
+
72
166
  def __enter__(
73
167
  self,
74
168
  ) -> set[Dependency]:
@@ -83,10 +177,17 @@ class DependencyTracker:
83
177
  remains a usable snapshot after the context exits; clearing
84
178
  thread-local storage does not mutate sets that were already returned.
85
179
  """
86
- _dependency_storage.depth += 1
87
- _dependency_storage.dependencies.append(_TrackedDependencySet())
88
- _dependency_storage.stack_version += 1
89
- return _dependency_storage.dependencies[_dependency_storage.depth]
180
+ storage = _dependency_storage
181
+ scope_storage = self._scope_storage
182
+ if not hasattr(scope_storage, "scopes"):
183
+ scope_storage.scopes = []
184
+ scopes: list[tuple[int, _TrackedDependencySet]] = scope_storage.scopes
185
+ generation = storage.generation
186
+ collector = _TrackedDependencySet()
187
+ scopes.append((generation, collector))
188
+ storage.dependencies.append(collector)
189
+ storage.stack_version += 1
190
+ return collector
90
191
 
91
192
  def __exit__(
92
193
  self,
@@ -107,16 +208,24 @@ class DependencyTracker:
107
208
  `reset_thread_local_storage()` or otherwise without an active context is
108
209
  a no-op.
109
210
  """
110
- if _dependency_storage.depth < 0:
211
+ storage = _dependency_storage
212
+ scope_storage = getattr(self, "_scope_storage", None)
213
+ scopes = getattr(scope_storage, "scopes", None)
214
+ if not scopes:
111
215
  return
112
- if _dependency_storage.depth == 0:
113
- self.reset_thread_local_storage()
216
+ generation, collector = scopes.pop()
217
+ if (
218
+ generation != storage.generation
219
+ or not storage.dependencies
220
+ or storage.dependencies[-1] is not collector
221
+ ):
114
222
  return
115
- _dependency_storage.dependencies.pop()
116
- _dependency_storage.depth -= 1
117
- _dependency_storage.stack_version += 1
118
- _dependency_storage.last_dependency = None
119
- _dependency_storage.last_dependency_stack_version = -1
223
+ storage.dependencies.pop()
224
+ storage.stack_version += 1
225
+ storage.last_dependency = None
226
+ storage.last_dependency_stack_version = -1
227
+ if not storage.dependencies and not storage.captures:
228
+ _clear_duplicate_state(storage)
120
229
 
121
230
  @staticmethod
122
231
  def track(
@@ -164,7 +273,7 @@ class DependencyTracker:
164
273
  ) -> None:
165
274
  """Record an already-validated dependency tuple in active collectors."""
166
275
  storage = _dependency_storage
167
- if storage.depth < 0:
276
+ if not storage.dependencies and not storage.captures:
168
277
  return
169
278
  if storage.last_dependency_stack_version == storage.stack_version:
170
279
  last_dependency = storage.last_dependency
@@ -181,11 +290,10 @@ class DependencyTracker:
181
290
  storage.seen_dependencies_stack_version = storage.stack_version
182
291
  elif dependency in storage.seen_dependencies:
183
292
  return
184
- if storage.depth == 0:
185
- storage.dependencies[0].add(dependency)
186
- else:
187
- for dep_set in storage.dependencies:
188
- dep_set.add(dependency)
293
+ for dep_set in storage.dependencies:
294
+ dep_set.add(dependency)
295
+ if storage.captures:
296
+ storage.captures[-1].add(dependency)
189
297
  storage.last_dependency = dependency
190
298
  storage.last_dependency_stack_version = storage.stack_version
191
299
  storage.seen_dependencies.add(dependency)
@@ -193,15 +301,42 @@ class DependencyTracker:
193
301
  @staticmethod
194
302
  def _track_many_validated(dependencies: Iterable[Dependency]) -> None:
195
303
  """Record already-validated dependency tuples in active collectors."""
196
- if _dependency_storage.depth < 0:
304
+ storage = _dependency_storage
305
+ if not storage.dependencies and not storage.captures:
306
+ return
307
+ if type(dependencies) in (tuple, frozenset):
308
+ if storage.dependencies:
309
+ for dep_set in storage.dependencies:
310
+ dep_set.update(dependencies)
311
+ if storage.captures:
312
+ storage.captures[-1].attach(snapshot_from_dependencies(dependencies))
197
313
  return
198
- reusable_dependencies: Collection[Dependency]
199
- if isinstance(dependencies, Collection):
200
- reusable_dependencies = dependencies
201
- else:
202
- reusable_dependencies = tuple(dependencies)
203
- for dep_set in _dependency_storage.dependencies:
204
- dep_set.update(reusable_dependencies)
314
+ frozen_dependencies = tuple(dependencies)
315
+ for dep_set in storage.dependencies:
316
+ dep_set.update(frozen_dependencies)
317
+ if storage.captures:
318
+ storage.captures[-1].attach(snapshot_from_dependencies(frozen_dependencies))
319
+
320
+ @staticmethod
321
+ def _capture() -> _DependencyCaptureScope:
322
+ """Create a private graph capture scope for cache implementations."""
323
+ return _DependencyCaptureScope()
324
+
325
+ @staticmethod
326
+ def _attach_snapshot(snapshot: DependencySnapshot) -> None:
327
+ """Attach cached graph metadata without flattening private parents."""
328
+ storage = _dependency_storage
329
+ if storage.captures:
330
+ storage.captures[-1].attach(snapshot)
331
+ if storage.dependencies:
332
+ dependencies = materialize_dependencies(snapshot)
333
+ for dep_set in storage.dependencies:
334
+ dep_set.update(dependencies)
335
+
336
+ @staticmethod
337
+ def _materialize_snapshot(snapshot: DependencySnapshot) -> set[Dependency]:
338
+ """Expose one trusted mutable publication set for a snapshot boundary."""
339
+ return _CapturedDependencySet(materialize_dependencies(snapshot))
205
340
 
206
341
  @staticmethod
207
342
  def _dependencies_are_tracker_captured(dependencies: object) -> bool:
@@ -211,7 +346,7 @@ class DependencyTracker:
211
346
  @staticmethod
212
347
  def is_active() -> bool:
213
348
  """Return whether dependency tracking is active for this execution context."""
214
- return _dependency_storage.depth >= 0
349
+ return bool(_dependency_storage.dependencies or _dependency_storage.captures)
215
350
 
216
351
  @staticmethod
217
352
  def reset_thread_local_storage() -> None:
@@ -3,11 +3,16 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Iterable, Mapping
6
- from dataclasses import dataclass
6
+ from dataclasses import dataclass, field
7
7
  from hashlib import sha256
8
8
  from typing import Protocol, TypeGuard, cast
9
9
 
10
10
  from general_manager.cache.cache_tracker import DependencyTracker
11
+ from general_manager.cache._dependency_graph import (
12
+ DependencySnapshot,
13
+ empty_dependency_snapshot,
14
+ snapshot_from_dependencies,
15
+ )
11
16
  from general_manager.cache.dependency_index import Dependency
12
17
 
13
18
  DEPENDENCY_CACHE_ENTRY_VERSION = 2
@@ -131,11 +136,41 @@ class DependencyCacheHit:
131
136
 
132
137
  value: object
133
138
  dependencies: frozenset[Dependency]
139
+ _dependency_root: DependencySnapshot | None = field(
140
+ init=False,
141
+ repr=False,
142
+ compare=False,
143
+ )
144
+
145
+ def __post_init__(self) -> None:
146
+ """Freeze caller-supplied metadata before retaining a graph leaf."""
147
+ dependencies = frozenset(self.dependencies)
148
+ object.__setattr__(self, "dependencies", dependencies)
149
+ object.__setattr__(
150
+ self,
151
+ "_dependency_root",
152
+ snapshot_from_dependencies(dependencies) if dependencies else None,
153
+ )
154
+
155
+ @property
156
+ def dependency_root(self) -> DependencySnapshot:
157
+ """Return this hit's immutable dependency leaf."""
158
+ return self._dependency_root or empty_dependency_snapshot()
134
159
 
135
160
 
136
161
  class _TrustedDependencyCacheHit(DependencyCacheHit):
137
162
  """Cache hit whose dependencies were captured by DependencyTracker."""
138
163
 
164
+ __slots__ = ()
165
+
166
+
167
+ def _trusted_dependency_cache_hit(
168
+ value: object,
169
+ dependencies: frozenset[Dependency],
170
+ ) -> DependencyCacheHit:
171
+ """Build an in-process hit whose frozen graph may be attached directly."""
172
+ return _TrustedDependencyCacheHit(value=value, dependencies=dependencies)
173
+
139
174
 
140
175
  class DependencyCacheBackend(Protocol):
141
176
  """Minimal cache backend shape for dependency-cache reads and writes."""
@@ -482,7 +517,7 @@ def replay_dependency_cache_hit(hit: DependencyCacheHit) -> None:
482
517
  tuple uses an unsupported operation.
483
518
  """
484
519
  if isinstance(hit, _TrustedDependencyCacheHit):
485
- DependencyTracker._track_many_validated(hit.dependencies)
520
+ DependencyTracker._attach_snapshot(hit.dependency_root)
486
521
  return
487
522
  for class_name, operation, identifier in hit.dependencies:
488
523
  DependencyTracker.track(class_name, operation, identifier)
@@ -158,13 +158,17 @@ class ModelDependencyCollector:
158
158
  Returns:
159
159
  None
160
160
  """
161
- if args and isinstance(args[0], GeneralManager):
162
- inner_self = args[0]
163
- for attr_val in inner_self.__dict__.values():
164
- for dependency_tuple in ModelDependencyCollector.collect(attr_val):
165
- dependencies.add(dependency_tuple)
161
+ for dependency in ModelDependencyCollector._iter_args(args, kwargs):
162
+ dependencies.add(dependency)
166
163
 
167
- for dependency_tuple in ModelDependencyCollector.collect(args):
168
- dependencies.add(dependency_tuple)
169
- for dependency_tuple in ModelDependencyCollector.collect(kwargs):
170
- dependencies.add(dependency_tuple)
164
+ @staticmethod
165
+ def _iter_args(
166
+ args: tuple[object, ...],
167
+ kwargs: Mapping[str, object],
168
+ ) -> Iterator[Dependency]:
169
+ """Yield argument dependencies using the public ``add_args`` order."""
170
+ if args and isinstance(args[0], GeneralManager):
171
+ for attr_val in args[0].__dict__.values():
172
+ yield from ModelDependencyCollector.collect(attr_val)
173
+ yield from ModelDependencyCollector.collect(args)
174
+ yield from ModelDependencyCollector.collect(kwargs)