GeneralManager 0.60.0__tar.gz → 0.60.1__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 (259) hide show
  1. {generalmanager-0.60.0/src/GeneralManager.egg-info → generalmanager-0.60.1}/PKG-INFO +1 -1
  2. {generalmanager-0.60.0 → generalmanager-0.60.1}/pyproject.toml +1 -1
  3. {generalmanager-0.60.0 → generalmanager-0.60.1/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/database_bucket.py +224 -16
  5. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/cache_tracker.py +12 -4
  6. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_cache.py +15 -5
  7. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_matching.py +66 -5
  8. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_shards.py +2 -0
  9. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/run_context.py +167 -1
  10. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/signals.py +7 -0
  11. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/base_interface.py +74 -0
  12. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/support.py +160 -5
  13. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +195 -9
  14. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/general_manager.py +85 -12
  15. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/meta.py +62 -4
  16. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/measurement/measurement.py +118 -25
  17. generalmanager-0.60.1/src/general_manager/utils/make_cache_key.py +114 -0
  18. generalmanager-0.60.0/src/general_manager/utils/make_cache_key.py +0 -43
  19. {generalmanager-0.60.0 → generalmanager-0.60.1}/LICENSE +0 -0
  20. {generalmanager-0.60.0 → generalmanager-0.60.1}/README.md +0 -0
  21. {generalmanager-0.60.0 → generalmanager-0.60.1}/setup.cfg +0 -0
  22. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
  23. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  24. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/requires.txt +0 -0
  25. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/top_level.txt +0 -0
  26. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/__init__.py +0 -0
  27. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/__init__.py +0 -0
  28. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/api.py +0 -0
  29. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/bucket.py +0 -0
  30. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/cache.py +0 -0
  31. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/dataframes.py +0 -0
  32. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/factory.py +0 -0
  33. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/general_manager.py +0 -0
  34. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/interface.py +0 -0
  35. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/manager.py +0 -0
  36. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/measurement.py +0 -0
  37. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/permission.py +0 -0
  38. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/rule.py +0 -0
  39. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/search.py +0 -0
  40. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/utils.py +0 -0
  41. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/__init__.py +0 -0
  42. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql.py +0 -0
  43. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_errors.py +0 -0
  44. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_mutations.py +0 -0
  45. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_prefetch.py +0 -0
  46. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_resolvers.py +0 -0
  47. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_search.py +0 -0
  48. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  49. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_subscriptions.py +0 -0
  50. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_view.py +0 -0
  51. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_warmup.py +0 -0
  52. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_warmup_registry.py +0 -0
  53. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
  54. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/mutation.py +0 -0
  55. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/property.py +0 -0
  56. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/registry.py +0 -0
  57. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/remote_api.py +0 -0
  58. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/remote_invalidation.py +0 -0
  59. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/remote_invalidation_client.py +0 -0
  60. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/apps.py +0 -0
  61. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bootstrap.py +0 -0
  62. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/__init__.py +0 -0
  63. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/base_bucket.py +0 -0
  64. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/calculation_bucket.py +0 -0
  65. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/group_bucket.py +0 -0
  66. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/indexing.py +0 -0
  67. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/request_bucket.py +0 -0
  68. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/__init__.py +0 -0
  69. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/cache_decorator.py +0 -0
  70. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_index.py +0 -0
  71. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_publish.py +0 -0
  72. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/model_dependency_collector.py +0 -0
  73. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/__init__.py +0 -0
  74. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/audit.py +0 -0
  75. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/bootstrap.py +0 -0
  76. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/checks.py +0 -0
  77. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/consumer.py +0 -0
  78. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/errors.py +0 -0
  79. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/__init__.py +0 -0
  80. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/__main__.py +0 -0
  81. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/baseline.py +0 -0
  82. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/diagnostics.py +0 -0
  83. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/fingerprints.py +0 -0
  84. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/fixtures.py +0 -0
  85. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/__init__.py +0 -0
  86. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
  87. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/contract.py +0 -0
  88. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
  89. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
  90. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/readiness.py +0 -0
  91. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/runner.py +0 -0
  92. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/traces.py +0 -0
  93. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/grounding.py +0 -0
  94. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/models.py +0 -0
  95. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/__init__.py +0 -0
  96. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/_shared.py +0 -0
  97. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/anthropic.py +0 -0
  98. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/base.py +0 -0
  99. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/google.py +0 -0
  100. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/ollama.py +0 -0
  101. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/openai.py +0 -0
  102. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/rate_limits.py +0 -0
  103. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/routing.py +0 -0
  104. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/schema_index.py +0 -0
  105. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/settings.py +0 -0
  106. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/signals.py +0 -0
  107. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/system_prompt.py +0 -0
  108. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/tool_metadata.py +0 -0
  109. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/tools.py +0 -0
  110. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/views.py +0 -0
  111. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/conf.py +0 -0
  112. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/dataframes/__init__.py +0 -0
  113. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/dataframes/measurements.py +0 -0
  114. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/__init__.py +0 -0
  115. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/auto_factory.py +0 -0
  116. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/factories.py +0 -0
  117. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/factory_methods.py +0 -0
  118. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/__init__.py +0 -0
  119. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/__init__.py +0 -0
  120. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/calculation.py +0 -0
  121. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/database.py +0 -0
  122. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  123. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/request.py +0 -0
  124. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/__init__.py +0 -0
  125. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/base.py +0 -0
  126. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/builtin.py +0 -0
  127. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  128. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  129. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  130. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/configuration.py +0 -0
  131. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  132. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  133. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  134. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  135. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  136. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  137. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/factory.py +0 -0
  138. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  139. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  140. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  141. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  142. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  143. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  144. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  145. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  146. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  147. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  148. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
  149. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  150. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  151. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/registry.py +0 -0
  152. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  153. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  154. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  155. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  156. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  157. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/__init__.py +0 -0
  158. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/calculation.py +0 -0
  159. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/database.py +0 -0
  160. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  161. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/read_only.py +0 -0
  162. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  163. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/request.py +0 -0
  164. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/__init__.py +0 -0
  165. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  166. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  167. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/capability_models.py +0 -0
  168. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/orm_interface.py +0 -0
  169. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/requests.py +0 -0
  170. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/__init__.py +0 -0
  171. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  172. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/errors.py +0 -0
  173. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/models.py +0 -0
  174. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/logging.py +0 -0
  175. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/chat_cleanup.py +0 -0
  176. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/graphql_warmup.py +0 -0
  177. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
  178. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/search_index.py +0 -0
  179. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/search_reconcile.py +0 -0
  180. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  181. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/shell.py +0 -0
  182. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  183. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  184. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/__init__.py +0 -0
  185. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/group_manager.py +0 -0
  186. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/input.py +0 -0
  187. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/measurement/__init__.py +0 -0
  188. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/measurement/measurement_field.py +0 -0
  189. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/metrics/__init__.py +0 -0
  190. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/metrics/graphql.py +0 -0
  191. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0001_initial.py +0 -0
  192. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  193. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  194. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
  195. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0004_search_index_state.py +0 -0
  196. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
  197. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
  198. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/__init__.py +0 -0
  199. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/models.py +0 -0
  200. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/__init__.py +0 -0
  201. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/audit.py +0 -0
  202. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/base_permission.py +0 -0
  203. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/graphql_capabilities.py +0 -0
  204. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/manager_based_permission.py +0 -0
  205. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/mutation_permission.py +0 -0
  206. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/permission_checks.py +0 -0
  207. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/permission_data_manager.py +0 -0
  208. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/utils.py +0 -0
  209. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/public_api_registry.py +0 -0
  210. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/py.typed +0 -0
  211. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/rule/__init__.py +0 -0
  212. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/rule/handler.py +0 -0
  213. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/rule/rule.py +0 -0
  214. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/__init__.py +0 -0
  215. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/async_tasks.py +0 -0
  216. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backend.py +0 -0
  217. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backend_registry.py +0 -0
  218. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/__init__.py +0 -0
  219. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/dev.py +0 -0
  220. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/meilisearch.py +0 -0
  221. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/opensearch.py +0 -0
  222. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/typesense.py +0 -0
  223. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/config.py +0 -0
  224. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/indexer.py +0 -0
  225. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/models.py +0 -0
  226. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/reconciliation.py +0 -0
  227. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/registry.py +0 -0
  228. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/tasks.py +0 -0
  229. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/utils.py +0 -0
  230. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/seeding/__init__.py +0 -0
  231. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/seeding/manager_landscape.py +0 -0
  232. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/__init__.py +0 -0
  233. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/args_to_kwargs.py +0 -0
  234. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/filter_parser.py +0 -0
  235. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/format_string.py +0 -0
  236. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/json_encoder.py +0 -0
  237. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/none_to_zero.py +0 -0
  238. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/path_mapping.py +0 -0
  239. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/public_api.py +0 -0
  240. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/testing.py +0 -0
  241. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/type_checks.py +0 -0
  242. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/__init__.py +0 -0
  243. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/actions.py +0 -0
  244. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backend_registry.py +0 -0
  245. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/__init__.py +0 -0
  246. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/celery.py +0 -0
  247. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/local.py +0 -0
  248. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/n8n.py +0 -0
  249. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/config.py +0 -0
  250. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/engine.py +0 -0
  251. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/event_registry.py +0 -0
  252. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/events.py +0 -0
  253. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/models.py +0 -0
  254. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/signal_bridge.py +0 -0
  255. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/tasks.py +0 -0
  256. {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/telemetry.py +0 -0
  257. {generalmanager-0.60.0 → generalmanager-0.60.1}/tests/test_settings.py +0 -0
  258. {generalmanager-0.60.0 → generalmanager-0.60.1}/tests/test_urls.py +0 -0
  259. {generalmanager-0.60.0 → generalmanager-0.60.1}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.60.0
3
+ Version: 0.60.1
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: MIT License
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GeneralManager"
7
- version = "0.60.0"
7
+ version = "0.60.1"
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.60.0
3
+ Version: 0.60.1
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: MIT License
@@ -27,6 +27,9 @@ QueryAnnotationCallable = Callable[
27
27
  models.QuerySet[models.Model],
28
28
  ]
29
29
  MAX_RUN_SCOPED_BUCKET_RESULT_ROWS = 1000
30
+ _QUERY_SIGNATURE_NOT_COMPUTED = object()
31
+ _FIRST_ROW_CACHE_MISS = object()
32
+ _FIRST_ROW_CACHE_NONE = object()
30
33
 
31
34
 
32
35
  class DatabaseBucketTypeMismatchError(TypeError):
@@ -251,6 +254,79 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
251
254
  self._sort_keys = sort_keys
252
255
  self._sort_reverse = sort_reverse
253
256
  self._run_scoped_cacheable = run_scoped_cacheable
257
+ self._query_signature_cache: tuple[Hashable, ...] | None | object = (
258
+ _QUERY_SIGNATURE_NOT_COMPUTED
259
+ )
260
+ self._trusted_query_signature: Hashable | None = None
261
+
262
+ def _set_trusted_query_signature(self, signature: Hashable | None) -> None:
263
+ """Set an internal non-SQL signature for framework-built querysets."""
264
+ self._trusted_query_signature = signature
265
+ self._query_signature_cache = _QUERY_SIGNATURE_NOT_COMPUTED
266
+
267
+ def _copy_for_run_context_reuse(self) -> DatabaseBucket[GeneralManagerType]:
268
+ """Return an unexposed bucket copy that reuses the same trusted queryset."""
269
+
270
+ bucket = self.__class__(
271
+ self._data,
272
+ self._manager_class,
273
+ self.filters,
274
+ self.excludes,
275
+ search_date=self._search_date,
276
+ sort_keys=self._sort_keys,
277
+ sort_reverse=self._sort_reverse,
278
+ run_scoped_cacheable=self._run_scoped_cacheable,
279
+ )
280
+ bucket._set_trusted_query_signature(self._trusted_query_signature)
281
+ return bucket
282
+
283
+ @staticmethod
284
+ def _freeze_trusted_signature_payload(value: object) -> Hashable:
285
+ if isinstance(value, Mapping):
286
+ return tuple(
287
+ (
288
+ str(key),
289
+ DatabaseBucket._freeze_trusted_signature_payload(item_value),
290
+ )
291
+ for key, item_value in sorted(
292
+ value.items(),
293
+ key=lambda item: str(item[0]),
294
+ )
295
+ )
296
+ if isinstance(value, (list, tuple)):
297
+ return tuple(
298
+ DatabaseBucket._freeze_trusted_signature_payload(item) for item in value
299
+ )
300
+ if isinstance(value, (set, frozenset)):
301
+ return tuple(
302
+ sorted(
303
+ (
304
+ DatabaseBucket._freeze_trusted_signature_payload(item)
305
+ for item in value
306
+ ),
307
+ key=repr,
308
+ )
309
+ )
310
+ if isinstance(value, models.Model):
311
+ return ("model", value.__class__, value.pk)
312
+ try:
313
+ hash(value)
314
+ except TypeError:
315
+ return ("serialized", serialize_dependency_identifier(value))
316
+ return value
317
+
318
+ def _trusted_query_signature_with(
319
+ self,
320
+ operation: str,
321
+ kwargs: Mapping[str, object],
322
+ ) -> Hashable | None:
323
+ if self._trusted_query_signature is None:
324
+ return None
325
+ return (
326
+ self._trusted_query_signature,
327
+ operation,
328
+ self._freeze_trusted_signature_payload(kwargs),
329
+ )
254
330
 
255
331
  def __reduce__(self) -> str | tuple[object, ...]:
256
332
  """
@@ -365,27 +441,50 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
365
441
  tuple[Hashable, ...] | None: Cache key components for equivalent
366
442
  queryset results, or ``None`` when reuse should be bypassed.
367
443
  """
444
+ if self._query_signature_cache is not _QUERY_SIGNATURE_NOT_COMPUTED:
445
+ return cast(tuple[Hashable, ...] | None, self._query_signature_cache)
368
446
  if not self._run_scoped_cacheable:
447
+ self._query_signature_cache = None
369
448
  return None
449
+ if self._trusted_query_signature is not None:
450
+ signature = (
451
+ self._manager_class,
452
+ self._data.model,
453
+ self._data.db,
454
+ "trusted",
455
+ self._trusted_query_signature,
456
+ self._search_date,
457
+ self._sort_keys,
458
+ self._sort_reverse,
459
+ )
460
+ self._query_signature_cache = signature
461
+ return signature
370
462
  query = self._data.query
371
463
  if not isinstance(query, Query):
464
+ self._query_signature_cache = None
372
465
  return None
373
466
  if query.select_for_update:
467
+ self._query_signature_cache = None
374
468
  return None
375
469
  if query.combinator:
470
+ self._query_signature_cache = None
376
471
  return None
377
472
  if query.distinct:
473
+ self._query_signature_cache = None
378
474
  return None
379
475
  if getattr(self._data, "_prefetch_related_lookups", ()):
476
+ self._query_signature_cache = None
380
477
  return None
381
478
  deferred_loading = getattr(query, "deferred_loading", None)
382
479
  if isinstance(deferred_loading, tuple) and deferred_loading[0]:
480
+ self._query_signature_cache = None
383
481
  return None
384
482
  try:
385
483
  sql, params = self._data.query.sql_with_params()
386
484
  except (EmptyResultSet, FieldError, TypeError, ValueError):
485
+ self._query_signature_cache = None
387
486
  return None
388
- return (
487
+ signature = (
389
488
  self._manager_class,
390
489
  self._data.model,
391
490
  self._data.db,
@@ -395,6 +494,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
395
494
  self._sort_keys,
396
495
  self._sort_reverse,
397
496
  )
497
+ self._query_signature_cache = signature
498
+ return signature
398
499
 
399
500
  def _bucket_index_source_signature(self) -> Hashable:
400
501
  """Return a queryset signature when safe, otherwise use object identity."""
@@ -501,6 +602,38 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
501
602
  return None
502
603
  return cast(tuple[models.Model, ...], cached)
503
604
 
605
+ def _can_cache_run_scoped_managers(self) -> bool:
606
+ if self._manager_class.__init__ is not GeneralManager.__init__:
607
+ return False
608
+ return callable(
609
+ getattr(self._manager_class.Interface, "_from_trusted_orm_instance", None)
610
+ )
611
+
612
+ def _get_run_scoped_managers(self) -> tuple[GeneralManagerType, ...] | None:
613
+ """Load or reuse manager wrappers for a trusted row snapshot."""
614
+ if not self._can_cache_run_scoped_managers():
615
+ return None
616
+ context = current_calculation_run_context()
617
+ if context is None:
618
+ return None
619
+ signature = self._query_signature()
620
+ if signature is None:
621
+ return None
622
+ cached = context.get_orm_bucket_managers(signature)
623
+ if cached is not None:
624
+ managers = cast(tuple[GeneralManagerType, ...], cached)
625
+ for manager in managers:
626
+ self._manager_class._track_identification_dependency(
627
+ manager.identification
628
+ )
629
+ return managers
630
+ rows = self._get_run_scoped_rows()
631
+ if rows is None:
632
+ return None
633
+ managers = tuple(self._build_manager_from_instance(row) for row in rows)
634
+ context.set_orm_bucket_managers(signature, managers)
635
+ return managers
636
+
504
637
  @staticmethod
505
638
  def _snapshot_get_primary_key(
506
639
  kwargs: Mapping[str, LookupValue],
@@ -528,21 +661,33 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
528
661
  return kwargs["id"]
529
662
  return None
530
663
 
664
+ def _can_materialize_count_snapshot(self) -> bool:
665
+ """Return whether count/len may populate a bounded run-scoped snapshot."""
666
+ context = current_calculation_run_context()
667
+ if context is None:
668
+ return False
669
+ query = getattr(self._data, "query", None)
670
+ if not isinstance(query, Query):
671
+ return False
672
+ where = getattr(query, "where", None)
673
+ children = getattr(where, "children", None)
674
+ return bool(children)
675
+
531
676
  def _track_effective_dependencies(self) -> None:
532
677
  """Record the bucket's effective filter/exclude state when it is evaluated."""
533
678
  manager_name = self._manager_class.__name__
534
679
  normalized_filters = self._normalize_dependency_mapping(self.filters)
535
680
  normalized_excludes = self._normalize_dependency_mapping(self.excludes)
536
681
  if self.filters:
537
- DependencyTracker.track(
682
+ DependencyTracker._track_validated(
538
683
  manager_name,
539
684
  "filter",
540
685
  serialize_dependency_identifier(normalized_filters),
541
686
  )
542
687
  else:
543
- DependencyTracker.track(manager_name, "all", "")
688
+ DependencyTracker._track_validated(manager_name, "all", "")
544
689
  if self.excludes:
545
- DependencyTracker.track(
690
+ DependencyTracker._track_validated(
546
691
  manager_name,
547
692
  "exclude",
548
693
  serialize_dependency_identifier(normalized_excludes),
@@ -554,7 +699,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
554
699
  "excludes": normalized_excludes,
555
700
  "reverse": self._sort_reverse,
556
701
  }
557
- DependencyTracker.track(
702
+ DependencyTracker._track_validated(
558
703
  manager_name,
559
704
  "filter",
560
705
  serialize_dependency_identifier({f"__sort__{sort_key}": payload}),
@@ -576,6 +721,10 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
576
721
  GeneralManagerType: Manager instance for each primary key in the queryset.
577
722
  """
578
723
  self._track_effective_dependencies()
724
+ managers = self._get_run_scoped_managers()
725
+ if managers is not None:
726
+ yield from managers
727
+ return
579
728
  rows = self._get_run_scoped_rows()
580
729
  if rows is not None:
581
730
  for row in rows:
@@ -782,7 +931,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
782
931
  qs = qs.filter(pk__in=ids)
783
932
 
784
933
  merged_filter = self.__merge_filter_definitions(self.filters, **kwargs)
785
- return self.__class__(
934
+ bucket = self.__class__(
786
935
  qs,
787
936
  self._manager_class,
788
937
  merged_filter,
@@ -792,6 +941,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
792
941
  sort_reverse=self._sort_reverse,
793
942
  run_scoped_cacheable=self._run_scoped_cacheable,
794
943
  )
944
+ if not annotations and not python_filters:
945
+ bucket._set_trusted_query_signature(
946
+ self._trusted_query_signature_with("filter", orm_kwargs)
947
+ )
948
+ return bucket
795
949
 
796
950
  def exclude(self, **kwargs: LookupValue) -> DatabaseBucket[GeneralManagerType]:
797
951
  """
@@ -843,7 +997,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
843
997
  qs = qs.exclude(pk__in=ids)
844
998
 
845
999
  merged_exclude = self.__merge_filter_definitions(self.excludes, **kwargs)
846
- return self.__class__(
1000
+ bucket = self.__class__(
847
1001
  qs,
848
1002
  self._manager_class,
849
1003
  self.filters,
@@ -853,6 +1007,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
853
1007
  sort_reverse=self._sort_reverse,
854
1008
  run_scoped_cacheable=self._run_scoped_cacheable,
855
1009
  )
1010
+ if not annotations and not python_filters:
1011
+ bucket._set_trusted_query_signature(
1012
+ self._trusted_query_signature_with("exclude", orm_kwargs)
1013
+ )
1014
+ return bucket
856
1015
 
857
1016
  def first(self) -> GeneralManagerType | None:
858
1017
  """
@@ -875,7 +1034,23 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
875
1034
  if not primary_keys:
876
1035
  return None
877
1036
  return self._build_manager_from_primary_key(primary_keys[0])
1037
+ context = current_calculation_run_context()
1038
+ signature = self._query_signature() if context is not None else None
1039
+ if context is not None and signature is not None:
1040
+ cached = context.get_orm_bucket_first_row(
1041
+ signature,
1042
+ _FIRST_ROW_CACHE_MISS,
1043
+ )
1044
+ if cached is _FIRST_ROW_CACHE_NONE:
1045
+ return None
1046
+ if cached is not _FIRST_ROW_CACHE_MISS:
1047
+ return self._build_manager_from_instance(cast(models.Model, cached))
878
1048
  first_element = self._data.first()
1049
+ if context is not None and signature is not None:
1050
+ context.set_orm_bucket_first_row(
1051
+ signature,
1052
+ _FIRST_ROW_CACHE_NONE if first_element is None else first_element,
1053
+ )
879
1054
  if first_element is None:
880
1055
  return None
881
1056
  return self._build_manager_from_instance(first_element)
@@ -917,6 +1092,10 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
917
1092
  int: Number of represented rows.
918
1093
  """
919
1094
  self._track_effective_dependencies()
1095
+ if self._can_materialize_count_snapshot():
1096
+ rows = self._get_run_scoped_rows()
1097
+ if rows is not None:
1098
+ return len(rows)
920
1099
  primary_keys = self._peek_run_scoped_primary_keys()
921
1100
  if primary_keys is not None:
922
1101
  return len(primary_keys)
@@ -932,7 +1111,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
932
1111
  Returns:
933
1112
  DatabaseBucket[GeneralManagerType]: Bucket encapsulating `self._data.all()`.
934
1113
  """
935
- return self.__class__(
1114
+ bucket = self.__class__(
936
1115
  self._data.all(),
937
1116
  self._manager_class,
938
1117
  self.filters,
@@ -942,6 +1121,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
942
1121
  sort_reverse=self._sort_reverse,
943
1122
  run_scoped_cacheable=self._run_scoped_cacheable,
944
1123
  )
1124
+ bucket._set_trusted_query_signature(self._trusted_query_signature)
1125
+ return bucket
945
1126
 
946
1127
  def get(self, **kwargs: LookupValue) -> GeneralManagerType:
947
1128
  """
@@ -1027,21 +1208,43 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
1027
1208
  return self._build_manager_from_primary_key(primary_keys[item])
1028
1209
  return self._build_manager_from_instance(self._data[item])
1029
1210
 
1211
+ def __bool__(self) -> bool:
1212
+ """
1213
+ Return whether the bucket contains at least one row without counting all rows.
1214
+
1215
+ Truthiness is an existence check, not a cardinality request. Reuse any
1216
+ active run-context snapshot first, then cache a queryset ``exists()``
1217
+ result for equivalent trusted querysets in the same calculation run.
1218
+ """
1219
+ self._track_effective_dependencies()
1220
+ rows = self._peek_run_scoped_rows()
1221
+ if rows is not None:
1222
+ return bool(rows)
1223
+ primary_keys = self._peek_run_scoped_primary_keys()
1224
+ if primary_keys is not None:
1225
+ return bool(primary_keys)
1226
+ context = current_calculation_run_context()
1227
+ signature = self._query_signature() if context is not None else None
1228
+ if context is not None and signature is not None:
1229
+ cached = context.get_orm_bucket_exists(signature)
1230
+ if cached is not None:
1231
+ return bool(cached)
1232
+ exists = bool(self._data.exists())
1233
+ if context is not None and signature is not None:
1234
+ context.set_orm_bucket_exists(signature, exists)
1235
+ return exists
1236
+
1030
1237
  def __len__(self) -> int:
1031
1238
  """
1032
1239
  Return the number of rows represented by the bucket.
1033
1240
 
1034
- A safe run-scoped primary-key snapshot is reused when present; otherwise
1035
- this delegates to the queryset count.
1241
+ Delegates to `count()` so dependency tracking, run-scoped snapshots, and
1242
+ queryset fallback behavior stay aligned between both cardinality paths.
1036
1243
 
1037
1244
  Returns:
1038
1245
  int: Number of represented rows.
1039
1246
  """
1040
- self._track_effective_dependencies()
1041
- primary_keys = self._peek_run_scoped_primary_keys()
1042
- if primary_keys is not None:
1043
- return len(primary_keys)
1044
- return int(self._data.count())
1247
+ return self.count()
1045
1248
 
1046
1249
  def __str__(self) -> str:
1047
1250
  """
@@ -1169,7 +1372,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
1169
1372
  except (FieldError, TypeError, ValueError) as error:
1170
1373
  raise QuerysetOrderingError(error) from error
1171
1374
 
1172
- return self.__class__(
1375
+ bucket = self.__class__(
1173
1376
  qs,
1174
1377
  self._manager_class,
1175
1378
  self.filters,
@@ -1179,6 +1382,9 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
1179
1382
  sort_reverse=reverse,
1180
1383
  run_scoped_cacheable=self._run_scoped_cacheable,
1181
1384
  )
1385
+ if not annotations and not python_keys:
1386
+ bucket._set_trusted_query_signature(self._trusted_query_signature)
1387
+ return bucket
1182
1388
 
1183
1389
  def none(self) -> DatabaseBucket[GeneralManagerType]:
1184
1390
  """
@@ -1193,4 +1399,6 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
1193
1399
  """
1194
1400
  own = self.all()
1195
1401
  own._data = own._data.none()
1402
+ own._query_signature_cache = _QUERY_SIGNATURE_NOT_COMPUTED
1403
+ own._trusted_query_signature = None
1196
1404
  return own
@@ -135,12 +135,20 @@ class DependencyTracker:
135
135
  raise _InvalidDependencyTrackerValueError
136
136
  if operation not in _SUPPORTED_OPERATIONS:
137
137
  raise _InvalidDependencyTrackerOperationError(operation)
138
+ DependencyTracker._track_validated(class_name, operation, identifier)
139
+
140
+ @staticmethod
141
+ def _track_validated(
142
+ class_name: general_manager_name,
143
+ operation: filter_type,
144
+ identifier: str,
145
+ ) -> None:
146
+ """Record an already-validated dependency tuple in active collectors."""
138
147
  if _dependency_storage.depth < 0:
139
148
  return
140
- for dep_set in _dependency_storage.dependencies[
141
- : _dependency_storage.depth + 1
142
- ]:
143
- dep_set.add((class_name, operation, identifier))
149
+ dependency = (class_name, operation, identifier)
150
+ for dep_set in _dependency_storage.dependencies:
151
+ dep_set.add(dependency)
144
152
 
145
153
  @staticmethod
146
154
  def is_active() -> bool:
@@ -9,7 +9,8 @@ from typing import Protocol, TypeGuard, cast
9
9
  from general_manager.cache.cache_tracker import DependencyTracker
10
10
  from general_manager.cache.dependency_index import Dependency
11
11
 
12
- DEPENDENCY_CACHE_ENTRY_VERSION = 1
12
+ LEGACY_DEPENDENCY_CACHE_ENTRY_VERSION = 1
13
+ DEPENDENCY_CACHE_ENTRY_VERSION = 2
13
14
  _VALID_DEPENDENCY_ACTIONS = frozenset(
14
15
  {"filter", "exclude", "identification", "request_query", "all"}
15
16
  )
@@ -258,10 +259,19 @@ def _combined_payload_to_hit(
258
259
  ) -> DependencyCacheHit | None | _MissingSentinel:
259
260
  if not isinstance(payload, DependencyCacheEntry):
260
261
  return None
261
- if payload.version != DEPENDENCY_CACHE_ENTRY_VERSION:
262
- return _MISSING
263
- dependencies = _legacy_dependency_set(payload.dependencies)
264
- if dependencies is None:
262
+ if payload.version == LEGACY_DEPENDENCY_CACHE_ENTRY_VERSION:
263
+ dependencies = _legacy_dependency_set(payload.dependencies)
264
+ if dependencies is None:
265
+ return _MISSING
266
+ elif payload.version == DEPENDENCY_CACHE_ENTRY_VERSION:
267
+ # Legacy entries may contain arbitrary tuple-like data, so the
268
+ # _legacy_dependency_set path validates each dependency. Current entries
269
+ # come from make_dependency_cache_entry after that same validation flow,
270
+ # so keep deserialization on the frozenset type-check fast path.
271
+ if not isinstance(payload.dependencies, frozenset):
272
+ return _MISSING
273
+ dependencies = payload.dependencies
274
+ else:
265
275
  return _MISSING
266
276
  return DependencyCacheHit(
267
277
  value=payload.value,
@@ -8,6 +8,7 @@ import re
8
8
  from collections.abc import Callable, Mapping, Sequence, Set as AbstractSet
9
9
  from dataclasses import dataclass
10
10
  from datetime import date, datetime
11
+ from json.encoder import encode_basestring_ascii
11
12
  from typing import Literal, Protocol, cast
12
13
 
13
14
  LookupOperator = Literal[
@@ -29,6 +30,8 @@ SCAN_OPERATORS = frozenset(
29
30
  )
30
31
  SUPPORTED_LOOKUP_OPERATORS = EXACT_OPERATORS | SCAN_OPERATORS
31
32
  UNDEFINED = object()
33
+ _SCALAR_NORMALIZATION_MISS = object()
34
+ _SCALAR_SERIALIZATION_MISS = object()
32
35
 
33
36
 
34
37
  type NormalizedDependencyValue = (
@@ -62,6 +65,47 @@ class SupportsDependencyComparison(Protocol):
62
65
  ...
63
66
 
64
67
 
68
+ def _normalize_scalar_dependency_value(value: object) -> object:
69
+ """
70
+ Return the scalar-only equivalent of `normalize_dependency_value`.
71
+
72
+ This avoids the slower general path for simple scalars only, and its output
73
+ must remain equivalent to full normalization for every value it accepts.
74
+ """
75
+
76
+ if isinstance(value, datetime):
77
+ return value.isoformat()
78
+ if isinstance(value, date):
79
+ return value.isoformat()
80
+ if isinstance(value, (str, int, float, bool)) or value is None:
81
+ return value
82
+ return _SCALAR_NORMALIZATION_MISS
83
+
84
+
85
+ def _serialize_scalar_dependency_value(value: object) -> str | object:
86
+ """
87
+ Serialize simple scalars without the slower generic JSON path.
88
+
89
+ Outputs must remain equivalent to full normalization followed by
90
+ `json.dumps(..., sort_keys=True)`. Floats are intentionally excluded so the
91
+ caller can preserve Python's JSON spelling for finite and non-finite values.
92
+ """
93
+
94
+ if isinstance(value, str):
95
+ return encode_basestring_ascii(value)
96
+ if value is None:
97
+ return "null"
98
+ if value is True:
99
+ return "true"
100
+ if value is False:
101
+ return "false"
102
+ if type(value) is int:
103
+ return str(value)
104
+ if isinstance(value, date):
105
+ return encode_basestring_ascii(value.isoformat())
106
+ return _SCALAR_SERIALIZATION_MISS
107
+
108
+
65
109
  @dataclass(frozen=True, slots=True)
66
110
  class LookupSpec:
67
111
  """Parsed dependency lookup path and operator."""
@@ -75,6 +119,11 @@ def normalize_dependency_value(value: object) -> NormalizedDependencyValue:
75
119
  """Return a deterministic JSON-compatible representation for dependency data."""
76
120
  if isinstance(value, Mapping):
77
121
  mapping = cast(Mapping[object, object], value)
122
+ if len(mapping) == 1:
123
+ key, val = next(iter(mapping.items()))
124
+ normalized_value = _normalize_scalar_dependency_value(val)
125
+ if normalized_value is not _SCALAR_NORMALIZATION_MISS:
126
+ return {str(key): cast(NormalizedDependencyValue, normalized_value)}
78
127
  return {
79
128
  str(key): normalize_dependency_value(val)
80
129
  for key, val in sorted(mapping.items(), key=lambda item: str(item[0]))
@@ -101,12 +150,24 @@ def normalize_dependency_value(value: object) -> NormalizedDependencyValue:
101
150
 
102
151
  def serialize_normalized_value(value: object) -> str:
103
152
  """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)):
153
+ serialized_scalar = _serialize_scalar_dependency_value(value)
154
+ if serialized_scalar is not _SCALAR_SERIALIZATION_MISS:
155
+ return cast(str, serialized_scalar)
156
+ if isinstance(value, float):
107
157
  return json.dumps(value)
108
- if isinstance(value, date):
109
- return json.dumps(value.isoformat())
158
+ if isinstance(value, Mapping):
159
+ mapping = cast(Mapping[object, object], value)
160
+ if len(mapping) == 1:
161
+ key, val = next(iter(mapping.items()))
162
+ normalized_value = _normalize_scalar_dependency_value(val)
163
+ serialized_value = _serialize_scalar_dependency_value(normalized_value)
164
+ if serialized_value is not _SCALAR_SERIALIZATION_MISS:
165
+ return (
166
+ "{"
167
+ f"{encode_basestring_ascii(str(key))}: "
168
+ f"{cast(str, serialized_value)}"
169
+ "}"
170
+ )
110
171
  return json.dumps(normalize_dependency_value(value), sort_keys=True)
111
172
 
112
173
 
@@ -13,6 +13,7 @@ import hashlib
13
13
  from collections.abc import Iterable, Mapping
14
14
  from collections import defaultdict
15
15
  from dataclasses import dataclass, field
16
+ from functools import lru_cache
16
17
  from typing import Literal
17
18
 
18
19
  from django.core.cache import cache
@@ -377,6 +378,7 @@ def clear_legacy_dependency_index() -> set[str]:
377
378
  return cache_keys
378
379
 
379
380
 
381
+ @lru_cache(maxsize=16384)
380
382
  def _shard_keys_for_dependency(
381
383
  manager_name: str,
382
384
  action: DependencyAction,