GeneralManager 0.64.4__tar.gz → 0.65.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 (295) hide show
  1. {generalmanager-0.64.4/src/GeneralManager.egg-info → generalmanager-0.65.1}/PKG-INFO +6 -9
  2. {generalmanager-0.64.4 → generalmanager-0.65.1}/README.md +6 -9
  3. {generalmanager-0.64.4 → generalmanager-0.65.1}/pyproject.toml +1 -1
  4. {generalmanager-0.64.4 → generalmanager-0.65.1/src/GeneralManager.egg-info}/PKG-INFO +6 -9
  5. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/GeneralManager.egg-info/SOURCES.txt +5 -0
  6. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/general_manager.py +4 -0
  7. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/search.py +4 -0
  8. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_search.py +47 -6
  9. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/apps.py +9 -2
  10. generalmanager-0.65.1/src/general_manager/cache/data_change_context.py +93 -0
  11. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/signals.py +110 -52
  12. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm/mutations.py +27 -30
  13. generalmanager-0.65.1/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +20 -0
  14. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/public_api_registry.py +10 -0
  15. generalmanager-0.65.1/src/general_manager/search/async_tasks.py +507 -0
  16. generalmanager-0.65.1/src/general_manager/search/checks.py +259 -0
  17. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/config.py +41 -7
  18. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/indexer.py +164 -119
  19. generalmanager-0.65.1/src/general_manager/search/invalidation.py +1231 -0
  20. generalmanager-0.65.1/src/general_manager/search/m2m_invalidation.py +372 -0
  21. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/models.py +55 -37
  22. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/reconciliation.py +221 -53
  23. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/finalization.py +51 -2
  24. generalmanager-0.64.4/src/general_manager/search/async_tasks.py +0 -217
  25. {generalmanager-0.64.4 → generalmanager-0.65.1}/LICENSE +0 -0
  26. {generalmanager-0.64.4 → generalmanager-0.65.1}/setup.cfg +0 -0
  27. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  28. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/GeneralManager.egg-info/requires.txt +0 -0
  29. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/GeneralManager.egg-info/top_level.txt +0 -0
  30. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/__init__.py +0 -0
  31. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/__init__.py +0 -0
  32. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/api.py +3 -3
  33. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/bucket.py +0 -0
  34. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/cache.py +2 -2
  35. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/dataframes.py +2 -2
  36. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/factory.py +0 -0
  37. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/interface.py +0 -0
  38. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/manager.py +2 -2
  39. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/measurement.py +0 -0
  40. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/permission.py +2 -2
  41. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/rule.py +0 -0
  42. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/_types/utils.py +2 -2
  43. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/__init__.py +0 -0
  44. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql.py +0 -0
  45. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_errors.py +0 -0
  46. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_mutations.py +0 -0
  47. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_prefetch.py +0 -0
  48. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_relations.py +0 -0
  49. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_resolvers.py +0 -0
  50. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  51. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_subscriptions.py +0 -0
  52. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_view.py +0 -0
  53. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_warmup.py +0 -0
  54. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_warmup_registry.py +0 -0
  55. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
  56. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/mutation.py +0 -0
  57. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/notification_batching.py +0 -0
  58. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/property.py +0 -0
  59. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/registry.py +0 -0
  60. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/remote_api.py +0 -0
  61. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/remote_invalidation.py +0 -0
  62. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/api/remote_invalidation_client.py +0 -0
  63. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bootstrap.py +0 -0
  64. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/__init__.py +0 -0
  65. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/base_bucket.py +0 -0
  66. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/calculation_bucket.py +0 -0
  67. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/database_bucket.py +0 -0
  68. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/group_bucket.py +0 -0
  69. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/indexing.py +0 -0
  70. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/bucket/request_bucket.py +0 -0
  71. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/__init__.py +0 -0
  72. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/cache_decorator.py +0 -0
  73. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/cache_tracker.py +0 -0
  74. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/dependency_cache.py +0 -0
  75. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/dependency_index.py +0 -0
  76. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/dependency_matching.py +0 -0
  77. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/dependency_publish.py +0 -0
  78. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/dependency_shards.py +0 -0
  79. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/model_dependency_collector.py +0 -0
  80. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/cache/run_context.py +0 -0
  81. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/__init__.py +0 -0
  82. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/audit.py +0 -0
  83. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/bootstrap.py +0 -0
  84. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/checks.py +0 -0
  85. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/consumer.py +0 -0
  86. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/errors.py +0 -0
  87. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/__init__.py +0 -0
  88. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/__main__.py +0 -0
  89. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/baseline.py +0 -0
  90. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
  91. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
  92. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
  93. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
  94. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
  95. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
  96. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/diagnostics.py +0 -0
  97. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/fingerprints.py +0 -0
  98. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/fixtures.py +0 -0
  99. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/judges/__init__.py +0 -0
  100. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
  101. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/judges/contract.py +0 -0
  102. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
  103. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
  104. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/readiness.py +0 -0
  105. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/runner.py +0 -0
  106. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/evals/traces.py +0 -0
  107. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/grounding.py +0 -0
  108. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/models.py +0 -0
  109. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/__init__.py +0 -0
  110. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/_shared.py +0 -0
  111. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/anthropic.py +0 -0
  112. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/base.py +0 -0
  113. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/google.py +0 -0
  114. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/ollama.py +0 -0
  115. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/providers/openai.py +0 -0
  116. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/rate_limits.py +0 -0
  117. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/routing.py +0 -0
  118. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/schema_index.py +0 -0
  119. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/settings.py +0 -0
  120. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/signals.py +0 -0
  121. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/system_prompt.py +0 -0
  122. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/tool_metadata.py +0 -0
  123. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/tools.py +0 -0
  124. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/chat/views.py +0 -0
  125. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/conf.py +0 -0
  126. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/dataframes/__init__.py +0 -0
  127. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/dataframes/measurements.py +0 -0
  128. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/factory/__init__.py +0 -0
  129. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/factory/auto_factory.py +0 -0
  130. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/factory/factories.py +0 -0
  131. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/factory/factory_methods.py +0 -0
  132. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/__init__.py +0 -0
  133. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/base_interface.py +0 -0
  134. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/bundles/__init__.py +0 -0
  135. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/bundles/calculation.py +0 -0
  136. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/bundles/database.py +0 -0
  137. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  138. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/bundles/request.py +0 -0
  139. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/__init__.py +0 -0
  140. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/base.py +0 -0
  141. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/builtin.py +0 -0
  142. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  143. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  144. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  145. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/configuration.py +0 -0
  146. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  147. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  148. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  149. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  150. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  151. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  152. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/factory.py +0 -0
  153. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  154. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  155. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  156. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  157. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  158. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  159. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  160. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  161. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  162. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  163. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  164. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
  165. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  166. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  167. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/registry.py +0 -0
  168. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  169. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  170. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  171. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  172. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  173. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/__init__.py +0 -0
  174. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/calculation.py +0 -0
  175. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/database.py +0 -0
  176. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  177. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/read_only.py +0 -0
  178. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  179. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/interfaces/request.py +0 -0
  180. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/manifests/__init__.py +0 -0
  181. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  182. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  183. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/manifests/capability_models.py +0 -0
  184. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/orm_interface.py +0 -0
  185. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/requests.py +0 -0
  186. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/utils/__init__.py +0 -0
  187. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  188. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/utils/errors.py +0 -0
  189. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/utils/history.py +0 -0
  190. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/interface/utils/models.py +0 -0
  191. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/logging.py +0 -0
  192. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/chat_cleanup.py +0 -0
  193. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
  194. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/graphql_warmup.py +0 -0
  195. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
  196. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/search_index.py +0 -0
  197. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/search_reconcile.py +0 -0
  198. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  199. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/shell.py +0 -0
  200. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  201. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  202. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/manager/__init__.py +0 -0
  203. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/manager/general_manager.py +0 -0
  204. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/manager/group_manager.py +0 -0
  205. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/manager/input.py +0 -0
  206. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/manager/meta.py +0 -0
  207. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/measurement/__init__.py +0 -0
  208. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/measurement/measurement.py +0 -0
  209. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/measurement/measurement_field.py +0 -0
  210. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/metrics/__init__.py +0 -0
  211. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/metrics/graphql.py +0 -0
  212. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0001_initial.py +0 -0
  213. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  214. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  215. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
  216. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0004_search_index_state.py +0 -0
  217. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
  218. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
  219. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0007_upload_intent.py +0 -0
  220. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
  221. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
  222. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
  223. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/migrations/__init__.py +0 -0
  224. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/models.py +0 -0
  225. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/__init__.py +0 -0
  226. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/audit.py +0 -0
  227. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/base_permission.py +0 -0
  228. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/graphql_capabilities.py +0 -0
  229. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/manager_based_permission.py +0 -0
  230. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/mutation_permission.py +0 -0
  231. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/permission_checks.py +0 -0
  232. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/permission_data_manager.py +0 -0
  233. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/permission/utils.py +0 -0
  234. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/py.typed +0 -0
  235. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/rule/__init__.py +0 -0
  236. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/rule/handler.py +0 -0
  237. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/rule/rule.py +0 -0
  238. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/__init__.py +0 -0
  239. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backend.py +0 -0
  240. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backend_registry.py +0 -0
  241. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backends/__init__.py +0 -0
  242. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backends/dev.py +0 -0
  243. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backends/meilisearch.py +0 -0
  244. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backends/opensearch.py +0 -0
  245. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/backends/typesense.py +0 -0
  246. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/registry.py +0 -0
  247. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/tasks.py +0 -0
  248. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/search/utils.py +0 -0
  249. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/seeding/__init__.py +0 -0
  250. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/seeding/manager_landscape.py +0 -0
  251. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/__init__.py +0 -0
  252. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/adapters.py +0 -0
  253. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/checks.py +0 -0
  254. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/config.py +0 -0
  255. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/errors.py +0 -0
  256. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/graphql.py +0 -0
  257. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/graphql_types.py +0 -0
  258. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/metrics.py +0 -0
  259. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/models.py +0 -0
  260. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/public.py +0 -0
  261. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/s3.py +0 -0
  262. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/services.py +0 -0
  263. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/tokens.py +0 -0
  264. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/types.py +0 -0
  265. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/urls.py +0 -0
  266. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/uploads/views.py +0 -0
  267. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/__init__.py +0 -0
  268. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/args_to_kwargs.py +0 -0
  269. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/filter_parser.py +0 -0
  270. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/format_string.py +0 -0
  271. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/json_encoder.py +0 -0
  272. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/make_cache_key.py +0 -0
  273. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/none_to_zero.py +0 -0
  274. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/path_mapping.py +0 -0
  275. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/public_api.py +0 -0
  276. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/testing.py +0 -0
  277. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/utils/type_checks.py +0 -0
  278. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/__init__.py +0 -0
  279. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/actions.py +0 -0
  280. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/backend_registry.py +0 -0
  281. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/backends/__init__.py +0 -0
  282. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/backends/celery.py +0 -0
  283. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/backends/local.py +0 -0
  284. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/backends/n8n.py +0 -0
  285. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/config.py +0 -0
  286. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/engine.py +0 -0
  287. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/event_registry.py +0 -0
  288. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/events.py +0 -0
  289. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/models.py +0 -0
  290. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/signal_bridge.py +0 -0
  291. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/tasks.py +0 -0
  292. {generalmanager-0.64.4 → generalmanager-0.65.1}/src/general_manager/workflow/telemetry.py +0 -0
  293. {generalmanager-0.64.4 → generalmanager-0.65.1}/tests/test_settings.py +0 -0
  294. {generalmanager-0.64.4 → generalmanager-0.65.1}/tests/test_urls.py +0 -0
  295. {generalmanager-0.64.4 → generalmanager-0.65.1}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.64.4
3
+ Version: 0.65.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
@@ -144,15 +144,12 @@ and [interface concepts](https://timkleindick.github.io/general_manager/concepts
144
144
 
145
145
  ## Compatibility
146
146
 
147
- - Python 3.12 or newer
148
- - Django 5.2.15 or newer
149
- - CI exercises Python 3.12, 3.13, and 3.14 on SQLite
147
+ - Python 3.12 or later
148
+ - Django 5.2.15 or later
150
149
 
151
- GeneralManager builds on Django's database layer, but this project only claims
152
- backend support covered by its tests or maintained examples. SQLite,
153
- PostgreSQL, and MariaDB are exercised by CI and are fully supported. Other
154
- Django-supported backends may work, but are not currently claimed as supported
155
- by GeneralManager.
150
+ CI tests Python 3.12, 3.13, and 3.14 against SQLite, PostgreSQL and MariaDB.
151
+
152
+ Other database backends supported by Django may also work, but are not officially supported unless covered by GeneralManager’s test suite or maintained examples.
156
153
 
157
154
  ## Five-minute setup
158
155
 
@@ -55,15 +55,12 @@ and [interface concepts](https://timkleindick.github.io/general_manager/concepts
55
55
 
56
56
  ## Compatibility
57
57
 
58
- - Python 3.12 or newer
59
- - Django 5.2.15 or newer
60
- - CI exercises Python 3.12, 3.13, and 3.14 on SQLite
61
-
62
- GeneralManager builds on Django's database layer, but this project only claims
63
- backend support covered by its tests or maintained examples. SQLite,
64
- PostgreSQL, and MariaDB are exercised by CI and are fully supported. Other
65
- Django-supported backends may work, but are not currently claimed as supported
66
- by GeneralManager.
58
+ - Python 3.12 or later
59
+ - Django 5.2.15 or later
60
+
61
+ CI tests Python 3.12, 3.13, and 3.14 against SQLite, PostgreSQL and MariaDB.
62
+
63
+ Other database backends supported by Django may also work, but are not officially supported unless covered by GeneralManager’s test suite or maintained examples.
67
64
 
68
65
  ## Five-minute setup
69
66
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "GeneralManager"
7
- version = "0.64.4"
7
+ version = "0.65.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.64.4
3
+ Version: 0.65.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
@@ -144,15 +144,12 @@ and [interface concepts](https://timkleindick.github.io/general_manager/concepts
144
144
 
145
145
  ## Compatibility
146
146
 
147
- - Python 3.12 or newer
148
- - Django 5.2.15 or newer
149
- - CI exercises Python 3.12, 3.13, and 3.14 on SQLite
147
+ - Python 3.12 or later
148
+ - Django 5.2.15 or later
150
149
 
151
- GeneralManager builds on Django's database layer, but this project only claims
152
- backend support covered by its tests or maintained examples. SQLite,
153
- PostgreSQL, and MariaDB are exercised by CI and are fully supported. Other
154
- Django-supported backends may work, but are not currently claimed as supported
155
- by GeneralManager.
150
+ CI tests Python 3.12, 3.13, and 3.14 against SQLite, PostgreSQL and MariaDB.
151
+
152
+ Other database backends supported by Django may also work, but are not officially supported unless covered by GeneralManager’s test suite or maintained examples.
156
153
 
157
154
  ## Five-minute setup
158
155
 
@@ -59,6 +59,7 @@ src/general_manager/bucket/request_bucket.py
59
59
  src/general_manager/cache/__init__.py
60
60
  src/general_manager/cache/cache_decorator.py
61
61
  src/general_manager/cache/cache_tracker.py
62
+ src/general_manager/cache/data_change_context.py
62
63
  src/general_manager/cache/dependency_cache.py
63
64
  src/general_manager/cache/dependency_index.py
64
65
  src/general_manager/cache/dependency_matching.py
@@ -208,6 +209,7 @@ src/general_manager/migrations/0007_upload_intent.py
208
209
  src/general_manager/migrations/0008_upload_finalization_versions.py
209
210
  src/general_manager/migrations/0009_upload_cleanup_state.py
210
211
  src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py
212
+ src/general_manager/migrations/0011_search_index_state_dirty_generation.py
211
213
  src/general_manager/migrations/__init__.py
212
214
  src/general_manager/permission/__init__.py
213
215
  src/general_manager/permission/audit.py
@@ -225,8 +227,11 @@ src/general_manager/search/__init__.py
225
227
  src/general_manager/search/async_tasks.py
226
228
  src/general_manager/search/backend.py
227
229
  src/general_manager/search/backend_registry.py
230
+ src/general_manager/search/checks.py
228
231
  src/general_manager/search/config.py
229
232
  src/general_manager/search/indexer.py
233
+ src/general_manager/search/invalidation.py
234
+ src/general_manager/search/m2m_invalidation.py
230
235
  src/general_manager/search/models.py
231
236
  src/general_manager/search/reconciliation.py
232
237
  src/general_manager/search/registry.py
@@ -19,9 +19,11 @@ __all__ = [
19
19
  "RequestInterface",
20
20
  "Rule",
21
21
  "SearchBackend",
22
+ "SearchChange",
22
23
  "SearchConfigProtocol",
23
24
  "SearchConfigSpec",
24
25
  "SearchIndexer",
26
+ "SearchInvalidationRule",
25
27
  "configure_search_backend",
26
28
  "configure_search_backend_from_settings",
27
29
  "get_logger",
@@ -54,9 +56,11 @@ from general_manager.interface.interfaces.remote_manager import RemoteManagerInt
54
56
  from general_manager.interface.interfaces.request import RequestInterface
55
57
  from general_manager.rule.rule import Rule
56
58
  from general_manager.search.backend import SearchBackend
59
+ from general_manager.search.config import SearchChange
57
60
  from general_manager.search.config import SearchConfigProtocol
58
61
  from general_manager.search.config import SearchConfigSpec
59
62
  from general_manager.search.indexer import SearchIndexer
63
+ from general_manager.search.config import SearchInvalidationRule
60
64
  from general_manager.search.backend_registry import configure_search_backend
61
65
  from general_manager.search.backend_registry import (
62
66
  configure_search_backend_from_settings,
@@ -13,11 +13,13 @@ __all__ = [
13
13
  "SearchBackendError",
14
14
  "SearchBackendNotConfiguredError",
15
15
  "SearchBackendNotImplementedError",
16
+ "SearchChange",
16
17
  "SearchConfigProtocol",
17
18
  "SearchConfigSpec",
18
19
  "SearchDocument",
19
20
  "SearchHit",
20
21
  "SearchIndexer",
22
+ "SearchInvalidationRule",
21
23
  "SearchResult",
22
24
  "TypesenseBackend",
23
25
  "configure_search_backend",
@@ -37,11 +39,13 @@ from general_manager.search.backend import SearchBackendClientMissingError
37
39
  from general_manager.search.backend import SearchBackendError
38
40
  from general_manager.search.backend import SearchBackendNotConfiguredError
39
41
  from general_manager.search.backend import SearchBackendNotImplementedError
42
+ from general_manager.search.config import SearchChange
40
43
  from general_manager.search.config import SearchConfigProtocol
41
44
  from general_manager.search.config import SearchConfigSpec
42
45
  from general_manager.search.backend import SearchDocument
43
46
  from general_manager.search.backend import SearchHit
44
47
  from general_manager.search.indexer import SearchIndexer
48
+ from general_manager.search.config import SearchInvalidationRule
45
49
  from general_manager.search.backend import SearchResult
46
50
  from general_manager.search.backends.typesense import TypesenseBackend
47
51
  from general_manager.search.backend_registry import configure_search_backend
@@ -600,6 +600,38 @@ def get_filter_options(
600
600
  )
601
601
 
602
602
 
603
+ def _get_filter_relation_info(
604
+ field_type: type[GeneralManager],
605
+ attribute_name: str,
606
+ attr_info: Mapping[str, object],
607
+ ) -> Mapping[str, object]:
608
+ """Return explicit relation metadata or infer it for manager inputs."""
609
+ if attr_info.get("relation_kind") is not None:
610
+ return attr_info
611
+
612
+ interface = getattr(field_type, "Interface", None)
613
+ input_fields = getattr(interface, "input_fields", {})
614
+ input_field = (
615
+ input_fields.get(attribute_name) if isinstance(input_fields, dict) else None
616
+ )
617
+ input_type = getattr(input_field, "type", None)
618
+ if (
619
+ input_field is None
620
+ or resolve_general_manager_type(
621
+ input_type,
622
+ get_graphql_manager_registry(),
623
+ )
624
+ is None
625
+ ):
626
+ return attr_info
627
+
628
+ return {
629
+ **attr_info,
630
+ "relation_kind": "direct",
631
+ "filter_lookup": attr_info.get("filter_lookup", attribute_name),
632
+ }
633
+
634
+
603
635
  def get_relation_filter_option(
604
636
  attribute_type: object,
605
637
  attribute_name: str,
@@ -713,7 +745,12 @@ def create_filter_options(
713
745
 
714
746
  filter_fields: dict[str, GrapheneFieldType] = {}
715
747
  for attr_name, attr_info in field_type.Interface.get_attribute_types().items():
716
- attr_type = attr_info["type"]
748
+ effective_attr_info = _get_filter_relation_info(
749
+ field_type,
750
+ attr_name,
751
+ attr_info,
752
+ )
753
+ attr_type = effective_attr_info["type"]
717
754
  manager_type = resolve_general_manager_type(
718
755
  attr_type,
719
756
  get_graphql_manager_registry(),
@@ -722,7 +759,7 @@ def create_filter_options(
722
759
  relation_option = get_relation_filter_option(
723
760
  manager_type,
724
761
  attr_name,
725
- attr_info,
762
+ effective_attr_info,
726
763
  graphql_filter_type_registry,
727
764
  map_field_to_graphene_read,
728
765
  remaining_depth,
@@ -736,7 +773,10 @@ def create_filter_options(
736
773
  **{
737
774
  k: v
738
775
  for k, v in get_filter_options(
739
- attr_type, attr_name, map_field_to_graphene_read, attr_info
776
+ cast(type, attr_type),
777
+ attr_name,
778
+ map_field_to_graphene_read,
779
+ effective_attr_info,
740
780
  )
741
781
  if v is not None
742
782
  },
@@ -841,9 +881,10 @@ def normalize_filter_input(
841
881
  filters[key] = normalize_id_filter_value(field_type, key, value)
842
882
  continue
843
883
 
844
- attr_type = attr_info.get("type")
845
- relation_kind = attr_info.get("relation_kind")
846
- lookup = attr_info.get("filter_lookup", key)
884
+ effective_attr_info = _get_filter_relation_info(field_type, key, attr_info)
885
+ attr_type = effective_attr_info.get("type")
886
+ relation_kind = effective_attr_info.get("relation_kind")
887
+ lookup = effective_attr_info.get("filter_lookup", key)
847
888
  manager_type = resolve_general_manager_type(
848
889
  attr_type,
849
890
  get_graphql_manager_registry(),
@@ -168,8 +168,10 @@ class GeneralmanagerConfig(AppConfig):
168
168
  self.install_startup_hook_runner()
169
169
  self.register_system_checks()
170
170
  from general_manager.uploads.checks import register_upload_checks
171
+ from general_manager.search.checks import register_search_checks
171
172
 
172
173
  register_upload_checks()
174
+ register_search_checks()
173
175
  _autoload_app_managers_modules()
174
176
  self.initialize_general_manager_classes(
175
177
  GeneralManagerMeta.pending_attribute_initialization,
@@ -178,14 +180,19 @@ class GeneralmanagerConfig(AppConfig):
178
180
  handle_remote_api(GeneralManagerMeta.all_classes)
179
181
  configure_audit_logger_from_settings(settings)
180
182
  configure_search_backend_from_settings(settings)
183
+ from general_manager.search.invalidation import configure_search_invalidation
184
+ from general_manager.search.m2m_invalidation import (
185
+ configure_search_m2m_invalidation,
186
+ )
187
+
188
+ configure_search_invalidation()
189
+ configure_search_m2m_invalidation()
181
190
  configure_workflow_engine_from_settings(settings)
182
191
  configure_event_registry_from_settings(settings)
183
192
  configure_workflow_signal_bridge_from_settings(settings)
184
193
  configure_workflow_beat_schedule_from_settings(settings)
185
194
  configure_search_reconcile_beat_schedule_from_settings(settings)
186
195
  configure_graphql_warmup_beat_schedule_from_settings(settings)
187
- import general_manager.search.indexer as _search_indexer # noqa: F401
188
-
189
196
  from general_manager.conf import get_setting
190
197
 
191
198
  if get_setting("AUTOCREATE_GRAPHQL", False):
@@ -0,0 +1,93 @@
1
+ """Context-local ownership metadata for ORM data-change transactions."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterator
6
+ from contextlib import contextmanager
7
+ from contextvars import ContextVar
8
+ from dataclasses import dataclass
9
+
10
+
11
+ @dataclass
12
+ class _DataChangeTransaction:
13
+ """Live marker for one framework-owned transaction envelope."""
14
+
15
+ database_alias: str
16
+ caller_in_atomic_block: bool
17
+ active: bool = True
18
+
19
+
20
+ _owned_transactions: ContextVar[tuple[_DataChangeTransaction, ...]] = ContextVar(
21
+ "owned_data_change_transactions",
22
+ default=(),
23
+ )
24
+ _authorized_operations: ContextVar[tuple[_DataChangeTransaction, ...]] = ContextVar(
25
+ "authorized_data_change_operations",
26
+ default=(),
27
+ )
28
+
29
+
30
+ def _current_owner(database_alias: str) -> _DataChangeTransaction | None:
31
+ for owner in reversed(_owned_transactions.get()):
32
+ if owner.active and owner.database_alias == database_alias:
33
+ return owner
34
+ return None
35
+
36
+
37
+ @contextmanager
38
+ def own_data_change_transaction(
39
+ database_alias: str,
40
+ *,
41
+ caller_in_atomic_block: bool,
42
+ ) -> Iterator[None]:
43
+ """Record a live framework envelope without inspecting Django internals."""
44
+ owner = _DataChangeTransaction(
45
+ database_alias=database_alias,
46
+ caller_in_atomic_block=caller_in_atomic_block,
47
+ )
48
+ token = _owned_transactions.set((*_owned_transactions.get(), owner))
49
+ try:
50
+ yield
51
+ finally:
52
+ owner.active = False
53
+ _owned_transactions.reset(token)
54
+
55
+
56
+ @contextmanager
57
+ def authorize_data_change_operation(database_alias: str) -> Iterator[None]:
58
+ """Authorize only the decorated manager method to reuse its envelope."""
59
+ owner = _current_owner(database_alias)
60
+ if owner is None:
61
+ yield
62
+ return
63
+ token = _authorized_operations.set((*_authorized_operations.get(), owner))
64
+ try:
65
+ yield
66
+ finally:
67
+ _authorized_operations.reset(token)
68
+
69
+
70
+ def owns_data_change_transaction(database_alias: str) -> bool:
71
+ """Return whether this context has a live framework envelope for an alias."""
72
+ return _current_owner(database_alias) is not None
73
+
74
+
75
+ def is_data_change_operation_authorized(database_alias: str) -> bool:
76
+ """Return whether the current owner is running its decorated method body."""
77
+ owner = _current_owner(database_alias)
78
+ if owner is None:
79
+ return False
80
+ return any(
81
+ authorized is owner and authorized.active
82
+ for authorized in _authorized_operations.get()
83
+ )
84
+
85
+
86
+ def may_reuse_data_change_transaction(database_alias: str) -> bool:
87
+ """Conservatively authorize reuse when the manager opened the outer block."""
88
+ owner = _current_owner(database_alias)
89
+ return bool(
90
+ owner is not None
91
+ and not owner.caller_in_atomic_block
92
+ and is_data_change_operation_authorized(database_alias)
93
+ )
@@ -2,12 +2,19 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ from contextlib import nullcontext
5
6
  from copy import deepcopy
6
- from django.dispatch import Signal
7
- from typing import Callable, TypeVar, ParamSpec, cast, overload
8
-
9
7
  from functools import wraps
8
+ from typing import Callable, ParamSpec, TypeVar, cast, overload
9
+
10
+ from django.db import DEFAULT_DB_ALIAS, connections, transaction
11
+ from django.dispatch import Signal
12
+ from django.utils.connection import ConnectionDoesNotExist
10
13
 
14
+ from general_manager.cache.data_change_context import (
15
+ authorize_data_change_operation,
16
+ own_data_change_transaction,
17
+ )
11
18
  from general_manager.logging import get_logger
12
19
 
13
20
  post_data_change = Signal()
@@ -20,6 +27,16 @@ R = TypeVar("R")
20
27
  logger = get_logger("cache.signals")
21
28
 
22
29
 
30
+ def _caller_in_atomic_block(database_alias: str) -> bool:
31
+ """Read public transaction state when the configured alias is available."""
32
+ try:
33
+ return bool(connections[database_alias].in_atomic_block)
34
+ except ConnectionDoesNotExist:
35
+ # Preserve lightweight callers that replace ``transaction.atomic`` in
36
+ # isolation. A real atomic call will still reject an unknown alias.
37
+ return False
38
+
39
+
23
40
  @overload
24
41
  def data_change(func: Callable[P, R]) -> Callable[P, R]: ...
25
42
 
@@ -39,9 +56,12 @@ def data_change(
39
56
  clears run-scoped ORM bucket/index caches, emits `pre_data_change`, invokes
40
57
  the wrapped callable, then emits `post_data_change` with the changed
41
58
  instance, previous instance, action name, identification, and copied
42
- `_old_values` payload. GraphQL warm-up requeue keys collected during signal
43
- handling are drained only after the outermost active data-change barrier has
44
- closed; failed mutations drain pending keys but do not enqueue rewarm work.
59
+ `_old_values` payload. Both signals receive a per-call `change_context` and
60
+ the manager interface's database alias. ORM-backed signal dispatch and the
61
+ mutation share one transaction. GraphQL warm-up requeue keys collected
62
+ during signal handling are drained only after the outermost active
63
+ data-change barrier has closed; failed mutations drain pending keys but do
64
+ not enqueue rewarm work.
45
65
 
46
66
  Parameters:
47
67
  func: Function that performs a data mutation. Methods named `create`
@@ -85,6 +105,29 @@ def data_change(
85
105
  is_dependency_data_change_active,
86
106
  )
87
107
  from general_manager.cache.run_context import current_calculation_run_context
108
+ from general_manager.interface.orm_interface import OrmInterfaceBase
109
+
110
+ action = decorator_source.__name__
111
+ if action == "create":
112
+ sender = args[0]
113
+ instance_before = None
114
+ else:
115
+ instance_before = args[0]
116
+ sender = instance_before.__class__
117
+
118
+ interface = getattr(sender, "Interface", None)
119
+ is_orm_backed = isinstance(interface, type) and issubclass(
120
+ interface, OrmInterfaceBase
121
+ )
122
+ database_alias = DEFAULT_DB_ALIAS
123
+ if is_orm_backed:
124
+ database_alias = getattr(interface, "database", None) or DEFAULT_DB_ALIAS
125
+ change_context: dict[str, object] = {}
126
+ signal_kwargs = {
127
+ **kwargs,
128
+ "change_context": change_context,
129
+ "database_alias": database_alias,
130
+ }
88
131
 
89
132
  primary_exc: BaseException | None = None
90
133
  completed = False
@@ -95,55 +138,70 @@ def data_change(
95
138
  context.clear_bucket_indexes()
96
139
  context.clear_trusted_orm_managers()
97
140
  try:
98
- action = func.__name__
99
- if func.__name__ == "create":
100
- sender = args[0]
101
- instance_before = None
102
- else:
103
- instance = args[0]
104
- sender = instance.__class__
105
- instance_before = instance
106
- pre_data_change.send(
107
- sender=sender,
108
- instance=instance_before,
109
- action=action,
110
- **kwargs,
141
+ transaction_context = (
142
+ transaction.atomic(using=database_alias)
143
+ if is_orm_backed
144
+ else nullcontext()
111
145
  )
112
- old_relevant_values = getattr(instance_before, "_old_values", {})
113
- pre_identification = deepcopy(
114
- getattr(instance_before, "identification", None)
146
+ caller_in_atomic_block = (
147
+ _caller_in_atomic_block(database_alias) if is_orm_backed else False
115
148
  )
116
- if isinstance(func, classmethod):
117
- inner = cast(Callable[P, R], func.__func__)
118
- result = inner(*args, **kwargs)
119
- else:
120
- result = func(*args, **kwargs)
121
-
122
- context = current_calculation_run_context()
123
- if context is not None:
124
- context.clear_orm_bucket_results()
125
- context.clear_bucket_indexes()
126
- context.clear_trusted_orm_managers()
127
-
128
- instance = result
129
- identification = getattr(instance, "identification", None)
130
- if identification is None:
131
- identification = pre_identification
132
-
133
- post_data_change.send(
134
- sender=sender,
135
- instance=instance,
136
- previous_instance=instance_before,
137
- identification=identification,
138
- action=action,
139
- old_relevant_values=old_relevant_values,
140
- **kwargs,
149
+ ownership_context = (
150
+ own_data_change_transaction(
151
+ database_alias,
152
+ caller_in_atomic_block=caller_in_atomic_block,
153
+ )
154
+ if is_orm_backed
155
+ else nullcontext()
141
156
  )
142
- if instance_before is not None:
143
- try:
144
- delattr(instance_before, "_old_values")
145
- except AttributeError:
146
- pass
157
+ with transaction_context, ownership_context:
158
+ pre_data_change.send(
159
+ sender=sender,
160
+ instance=instance_before,
161
+ action=action,
162
+ **signal_kwargs,
163
+ )
164
+ old_relevant_values = getattr(instance_before, "_old_values", {})
165
+ pre_identification = deepcopy(
166
+ getattr(instance_before, "identification", None)
167
+ )
168
+ operation_context = (
169
+ authorize_data_change_operation(database_alias)
170
+ if is_orm_backed
171
+ else nullcontext()
172
+ )
173
+ with operation_context:
174
+ if isinstance(func, classmethod):
175
+ inner = cast(Callable[P, R], func.__func__)
176
+ result = inner(*args, **kwargs)
177
+ else:
178
+ result = func(*args, **kwargs)
179
+
180
+ context = current_calculation_run_context()
181
+ if context is not None:
182
+ context.clear_orm_bucket_results()
183
+ context.clear_bucket_indexes()
184
+ context.clear_trusted_orm_managers()
185
+
186
+ instance = result
187
+ identification = getattr(instance, "identification", None)
188
+ if identification is None:
189
+ identification = pre_identification
190
+
191
+ post_data_change.send(
192
+ sender=sender,
193
+ instance=instance,
194
+ previous_instance=instance_before,
195
+ identification=identification,
196
+ action=action,
197
+ old_relevant_values=old_relevant_values,
198
+ **signal_kwargs,
199
+ )
200
+ if instance_before is not None:
201
+ try:
202
+ delattr(instance_before, "_old_values")
203
+ except AttributeError:
204
+ pass
147
205
  completed = True
148
206
  except BaseException as error:
149
207
  primary_exc = error