GeneralManager 0.47.0__tar.gz → 0.49.0__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 (199) hide show
  1. {generalmanager-0.47.0/src/GeneralManager.egg-info → generalmanager-0.49.0}/PKG-INFO +1 -1
  2. {generalmanager-0.47.0 → generalmanager-0.49.0}/pyproject.toml +1 -1
  3. {generalmanager-0.47.0 → generalmanager-0.49.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bucket/database_bucket.py +176 -1
  5. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/cache_decorator.py +41 -21
  6. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/dependency_cache.py +10 -0
  7. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/dependency_index.py +17 -1
  8. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/dependency_publish.py +91 -1
  9. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/run_context.py +111 -6
  10. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/signals.py +4 -0
  11. {generalmanager-0.47.0 → generalmanager-0.49.0}/LICENSE +0 -0
  12. {generalmanager-0.47.0 → generalmanager-0.49.0}/README.md +0 -0
  13. {generalmanager-0.47.0 → generalmanager-0.49.0}/setup.cfg +0 -0
  14. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
  15. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  16. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/requires.txt +0 -0
  17. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
  18. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/__init__.py +0 -0
  19. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/__init__.py +0 -0
  20. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/api.py +0 -0
  21. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/bucket.py +0 -0
  22. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/cache.py +0 -0
  23. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/factory.py +0 -0
  24. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/general_manager.py +0 -0
  25. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/interface.py +0 -0
  26. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/manager.py +0 -0
  27. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/measurement.py +0 -0
  28. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/permission.py +0 -0
  29. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/rule.py +0 -0
  30. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/search.py +0 -0
  31. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/_types/utils.py +0 -0
  32. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/__init__.py +0 -0
  33. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql.py +0 -0
  34. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_errors.py +0 -0
  35. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_mutations.py +0 -0
  36. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_prefetch.py +0 -0
  37. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_resolvers.py +0 -0
  38. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_search.py +0 -0
  39. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  40. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_subscriptions.py +0 -0
  41. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_view.py +0 -0
  42. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/mutation.py +0 -0
  43. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/property.py +0 -0
  44. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/registry.py +0 -0
  45. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/remote_api.py +0 -0
  46. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/remote_invalidation.py +0 -0
  47. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
  48. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/apps.py +0 -0
  49. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bootstrap.py +0 -0
  50. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bucket/__init__.py +0 -0
  51. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bucket/base_bucket.py +0 -0
  52. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bucket/calculation_bucket.py +0 -0
  53. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bucket/group_bucket.py +0 -0
  54. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/bucket/request_bucket.py +0 -0
  55. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/__init__.py +0 -0
  56. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/cache_tracker.py +0 -0
  57. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
  58. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/conf.py +0 -0
  59. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/factory/__init__.py +0 -0
  60. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/factory/auto_factory.py +0 -0
  61. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/factory/factories.py +0 -0
  62. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/factory/factory_methods.py +0 -0
  63. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/__init__.py +0 -0
  64. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/base_interface.py +0 -0
  65. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/__init__.py +0 -0
  66. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/calculation.py +0 -0
  67. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/database.py +0 -0
  68. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  69. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/request.py +0 -0
  70. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
  71. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/base.py +0 -0
  72. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
  73. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  74. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  75. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  76. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
  77. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  78. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  79. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  80. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  81. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  82. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  83. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/factory.py +0 -0
  84. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  85. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  86. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  87. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  88. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  89. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  90. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  91. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  92. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  93. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  94. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  95. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  96. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  97. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  98. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/registry.py +0 -0
  99. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  100. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  101. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  102. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  103. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  104. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
  105. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
  106. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/database.py +0 -0
  107. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  108. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
  109. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  110. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/request.py +0 -0
  111. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/__init__.py +0 -0
  112. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  113. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  114. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
  115. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/orm_interface.py +0 -0
  116. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/requests.py +0 -0
  117. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/__init__.py +0 -0
  118. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  119. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/errors.py +0 -0
  120. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/models.py +0 -0
  121. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/logging.py +0 -0
  122. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/management/commands/search_index.py +0 -0
  123. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  124. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/management/commands/shell.py +0 -0
  125. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  126. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  127. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/manager/__init__.py +0 -0
  128. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/manager/general_manager.py +0 -0
  129. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/manager/group_manager.py +0 -0
  130. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/manager/input.py +0 -0
  131. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/manager/meta.py +0 -0
  132. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/measurement/__init__.py +0 -0
  133. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/measurement/measurement.py +0 -0
  134. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/measurement/measurement_field.py +0 -0
  135. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/metrics/__init__.py +0 -0
  136. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/metrics/graphql.py +0 -0
  137. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/migrations/0001_initial.py +0 -0
  138. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  139. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  140. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/migrations/__init__.py +0 -0
  141. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/models.py +0 -0
  142. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/__init__.py +0 -0
  143. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/audit.py +0 -0
  144. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/base_permission.py +0 -0
  145. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
  146. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/manager_based_permission.py +0 -0
  147. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/mutation_permission.py +0 -0
  148. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/permission_checks.py +0 -0
  149. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/permission_data_manager.py +0 -0
  150. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/permission/utils.py +0 -0
  151. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/public_api_registry.py +0 -0
  152. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/py.typed +0 -0
  153. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/rule/__init__.py +0 -0
  154. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/rule/handler.py +0 -0
  155. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/rule/rule.py +0 -0
  156. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/__init__.py +0 -0
  157. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/async_tasks.py +0 -0
  158. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backend.py +0 -0
  159. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backend_registry.py +0 -0
  160. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backends/__init__.py +0 -0
  161. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backends/dev.py +0 -0
  162. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backends/meilisearch.py +0 -0
  163. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backends/opensearch.py +0 -0
  164. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/backends/typesense.py +0 -0
  165. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/config.py +0 -0
  166. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/indexer.py +0 -0
  167. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/registry.py +0 -0
  168. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/search/utils.py +0 -0
  169. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/seeding/__init__.py +0 -0
  170. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/seeding/manager_landscape.py +0 -0
  171. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/__init__.py +0 -0
  172. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/args_to_kwargs.py +0 -0
  173. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/filter_parser.py +0 -0
  174. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/format_string.py +0 -0
  175. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/json_encoder.py +0 -0
  176. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/make_cache_key.py +0 -0
  177. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/none_to_zero.py +0 -0
  178. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/path_mapping.py +0 -0
  179. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/public_api.py +0 -0
  180. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/testing.py +0 -0
  181. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/utils/type_checks.py +0 -0
  182. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/__init__.py +0 -0
  183. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/actions.py +0 -0
  184. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/backend_registry.py +0 -0
  185. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/__init__.py +0 -0
  186. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/celery.py +0 -0
  187. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/local.py +0 -0
  188. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/n8n.py +0 -0
  189. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/config.py +0 -0
  190. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/engine.py +0 -0
  191. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/event_registry.py +0 -0
  192. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/events.py +0 -0
  193. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/models.py +0 -0
  194. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/signal_bridge.py +0 -0
  195. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/tasks.py +0 -0
  196. {generalmanager-0.47.0 → generalmanager-0.49.0}/src/general_manager/workflow/telemetry.py +0 -0
  197. {generalmanager-0.47.0 → generalmanager-0.49.0}/tests/test_settings.py +0 -0
  198. {generalmanager-0.47.0 → generalmanager-0.49.0}/tests/test_urls.py +0 -0
  199. {generalmanager-0.47.0 → generalmanager-0.49.0}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.47.0
3
+ Version: 0.49.0
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.47.0"
7
+ version = "0.49.0"
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.47.0
3
+ Version: 0.49.0
4
4
  Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
5
5
  Author-email: Tim Kleindick <tkleindick@yahoo.de>
6
6
  License: MIT License
@@ -1,20 +1,24 @@
1
1
  """Database-backed bucket implementation for GeneralManager collections."""
2
2
 
3
3
  from __future__ import annotations
4
+ from collections.abc import Hashable
4
5
  from datetime import date, datetime
5
6
  from typing import Any, Generator, Type, TypeVar
6
7
 
7
- from django.core.exceptions import FieldError
8
+ from django.core.exceptions import EmptyResultSet, FieldError
8
9
  from django.db import models
10
+ from django.db.models.sql.query import Query
9
11
 
10
12
  from general_manager.bucket.base_bucket import Bucket
11
13
  from general_manager.cache.cache_tracker import DependencyTracker
12
14
  from general_manager.cache.dependency_index import serialize_dependency_identifier
15
+ from general_manager.cache.run_context import current_calculation_run_context
13
16
  from general_manager.manager.general_manager import GeneralManager
14
17
  from general_manager.utils.filter_parser import create_filter_function
15
18
 
16
19
  modelsModel = TypeVar("modelsModel", bound=models.Model)
17
20
  GeneralManagerType = TypeVar("GeneralManagerType", bound=GeneralManager)
21
+ MAX_RUN_SCOPED_BUCKET_RESULT_ROWS = 1000
18
22
 
19
23
 
20
24
  class DatabaseBucketTypeMismatchError(TypeError):
@@ -204,6 +208,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
204
208
  search_date: datetime | date | None = None,
205
209
  sort_keys: tuple[str, ...] | None = None,
206
210
  sort_reverse: bool = False,
211
+ run_scoped_cacheable: bool = True,
207
212
  ) -> None:
208
213
  """
209
214
  Instantiate a database-backed bucket with optional filter state.
@@ -214,6 +219,9 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
214
219
  filter_definitions (dict[str, list[Any]] | None): Pre-existing filter expressions captured from parent buckets.
215
220
  exclude_definitions (dict[str, list[Any]] | None): Pre-existing exclusion expressions captured from parent buckets.
216
221
  search_date (datetime | date | None): Optional timestamp applied when instantiating manager instances.
222
+ sort_keys (tuple[str, ...] | None): Property names used by a previous bucket sort operation.
223
+ sort_reverse (bool): Whether sorted keys should be interpreted in descending order for dependency tracking.
224
+ run_scoped_cacheable (bool): Whether terminal results from this bucket are safe to reuse inside the active calculation run.
217
225
 
218
226
  Returns:
219
227
  None
@@ -225,6 +233,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
225
233
  self._search_date = search_date
226
234
  self._sort_keys = sort_keys
227
235
  self._sort_reverse = sort_reverse
236
+ self._run_scoped_cacheable = run_scoped_cacheable
228
237
 
229
238
  def __reduce__(self) -> str | tuple[Any, ...]:
230
239
  """
@@ -281,6 +290,127 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
281
290
  for key, values in definitions.items()
282
291
  }
283
292
 
293
+ def _query_signature(self) -> tuple[Hashable, ...] | None:
294
+ """
295
+ Return a conservative run-scoped cache signature for this queryset.
296
+
297
+ The signature is only produced for queryset shapes whose SQL, database
298
+ alias, manager class, model, search date, and sort state can safely
299
+ distinguish equivalent terminal results. Unsupported or risky query
300
+ forms return ``None`` so callers fall back to normal ORM evaluation.
301
+
302
+ Returns:
303
+ tuple[Hashable, ...] | None: Cache key components for equivalent
304
+ queryset results, or ``None`` when reuse should be bypassed.
305
+ """
306
+ if not self._run_scoped_cacheable:
307
+ return None
308
+ query = self._data.query
309
+ if not isinstance(query, Query):
310
+ return None
311
+ if query.select_for_update:
312
+ return None
313
+ if query.combinator:
314
+ return None
315
+ if query.distinct:
316
+ return None
317
+ try:
318
+ sql, params = self._data.query.sql_with_params()
319
+ except (EmptyResultSet, FieldError, TypeError, ValueError):
320
+ return None
321
+ return (
322
+ self._manager_class,
323
+ self._data.model,
324
+ self._data.db,
325
+ sql,
326
+ tuple(params),
327
+ self._search_date,
328
+ self._sort_keys,
329
+ self._sort_reverse,
330
+ )
331
+
332
+ def _get_run_scoped_primary_keys(self) -> tuple[Any, ...] | None:
333
+ """
334
+ Load or reuse a bounded primary-key snapshot for this bucket.
335
+
336
+ The method materializes at most ``MAX_RUN_SCOPED_BUCKET_RESULT_ROWS``
337
+ primary keys and stores them in the active
338
+ :class:`CalculationRunContext`. Buckets without an active context,
339
+ without a safe signature, or above the materialization guardrail return
340
+ ``None`` so terminal operations continue through the database.
341
+
342
+ Returns:
343
+ tuple[Any, ...] | None: Cached or newly materialized primary keys,
344
+ or ``None`` when run-scoped reuse is unavailable.
345
+ """
346
+ context = current_calculation_run_context()
347
+ if context is None:
348
+ return None
349
+ signature = self._query_signature()
350
+ if signature is None:
351
+ return None
352
+ cached = context.get_orm_bucket_result(signature)
353
+ if cached is not None:
354
+ return cached # type: ignore[return-value]
355
+
356
+ primary_keys = tuple(
357
+ self._data.values_list("pk", flat=True)[
358
+ : MAX_RUN_SCOPED_BUCKET_RESULT_ROWS + 1
359
+ ]
360
+ )
361
+ if len(primary_keys) > MAX_RUN_SCOPED_BUCKET_RESULT_ROWS:
362
+ return None
363
+ context.set_orm_bucket_result(signature, primary_keys)
364
+ return primary_keys
365
+
366
+ def _peek_run_scoped_primary_keys(self) -> tuple[Any, ...] | None:
367
+ """
368
+ Return an already cached primary-key snapshot without evaluating the ORM.
369
+
370
+ Terminal operations such as ``count()`` and membership checks call this
371
+ helper so they can reuse a snapshot created by iteration without forcing
372
+ materialization on their own.
373
+
374
+ Returns:
375
+ tuple[Any, ...] | None: Cached primary keys for this bucket, or
376
+ ``None`` when no snapshot exists.
377
+ """
378
+ context = current_calculation_run_context()
379
+ if context is None:
380
+ return None
381
+ signature = self._query_signature()
382
+ if signature is None:
383
+ return None
384
+ cached = context.get_orm_bucket_result(signature)
385
+ if cached is None:
386
+ return None
387
+ return cached # type: ignore[return-value]
388
+
389
+ @staticmethod
390
+ def _snapshot_get_primary_key(kwargs: dict[str, Any]) -> Any | None:
391
+ """
392
+ Extract the primary key from a snapshot-safe ``get()`` lookup.
393
+
394
+ Only single-key ``pk`` and ``id`` lookups can be answered from the
395
+ cached primary-key tuple while preserving Django's ``QuerySet.get()``
396
+ semantics. All other lookup shapes return ``None`` and use the normal
397
+ ORM path.
398
+
399
+ Parameters:
400
+ kwargs (dict[str, Any]): Lookup arguments passed to ``get()``.
401
+
402
+ Returns:
403
+ Any | None: Requested primary key when the lookup is snapshot-safe,
404
+ otherwise ``None``.
405
+ """
406
+ if len(kwargs) != 1:
407
+ return None
408
+ if "pk" in kwargs:
409
+ return kwargs["pk"]
410
+ if "id" in kwargs:
411
+ return kwargs["id"]
412
+ return None
413
+
284
414
  def _track_effective_dependencies(self) -> None:
285
415
  """Record the bucket's effective filter/exclude state when it is evaluated."""
286
416
  manager_name = self._manager_class.__name__
@@ -321,6 +451,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
321
451
  GeneralManagerType: Manager instance for each primary key in the queryset.
322
452
  """
323
453
  self._track_effective_dependencies()
454
+ primary_keys = self._get_run_scoped_primary_keys()
455
+ if primary_keys is not None:
456
+ for primary_key in primary_keys:
457
+ yield self._build_manager(primary_key)
458
+ return
324
459
  for item in self._data:
325
460
  yield self._build_manager(item.pk)
326
461
 
@@ -365,6 +500,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
365
500
  search_date=self._search_date,
366
501
  sort_keys=self._sort_keys,
367
502
  sort_reverse=self._sort_reverse,
503
+ run_scoped_cacheable=False,
368
504
  )
369
505
 
370
506
  def __merge_filter_definitions(
@@ -502,6 +638,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
502
638
  search_date=search_date,
503
639
  sort_keys=self._sort_keys,
504
640
  sort_reverse=self._sort_reverse,
641
+ run_scoped_cacheable=self._run_scoped_cacheable,
505
642
  )
506
643
 
507
644
  def exclude(self, **kwargs: Any) -> DatabaseBucket[GeneralManagerType]:
@@ -549,6 +686,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
549
686
  search_date=search_date,
550
687
  sort_keys=self._sort_keys,
551
688
  sort_reverse=self._sort_reverse,
689
+ run_scoped_cacheable=self._run_scoped_cacheable,
552
690
  )
553
691
 
554
692
  def first(self) -> GeneralManagerType | None:
@@ -559,6 +697,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
559
697
  GeneralManagerType | None: First manager instance if available.
560
698
  """
561
699
  self._track_effective_dependencies()
700
+ primary_keys = self._peek_run_scoped_primary_keys()
701
+ if primary_keys is not None:
702
+ if not primary_keys:
703
+ return None
704
+ return self._build_manager(primary_keys[0])
562
705
  first_element = self._data.first()
563
706
  if first_element is None:
564
707
  return None
@@ -572,6 +715,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
572
715
  GeneralManagerType | None: Last manager instance if available.
573
716
  """
574
717
  self._track_effective_dependencies()
718
+ primary_keys = self._peek_run_scoped_primary_keys()
719
+ if primary_keys is not None:
720
+ if not primary_keys:
721
+ return None
722
+ return self._build_manager(primary_keys[-1])
575
723
  first_element = self._data.last()
576
724
  if first_element is None:
577
725
  return None
@@ -585,6 +733,9 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
585
733
  int: Number of queryset rows.
586
734
  """
587
735
  self._track_effective_dependencies()
736
+ primary_keys = self._peek_run_scoped_primary_keys()
737
+ if primary_keys is not None:
738
+ return len(primary_keys)
588
739
  return self._data.count()
589
740
 
590
741
  def all(self) -> DatabaseBucket[GeneralManagerType]:
@@ -602,6 +753,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
602
753
  search_date=self._search_date,
603
754
  sort_keys=self._sort_keys,
604
755
  sort_reverse=self._sort_reverse,
756
+ run_scoped_cacheable=self._run_scoped_cacheable,
605
757
  )
606
758
 
607
759
  def get(self, **kwargs: Any) -> GeneralManagerType:
@@ -619,6 +771,16 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
619
771
  models.MultipleObjectsReturned: Propagated when multiple rows satisfy the lookup.
620
772
  """
621
773
  self._track_effective_dependencies()
774
+ primary_keys = self._peek_run_scoped_primary_keys()
775
+ if primary_keys is not None:
776
+ requested_primary_key = self._snapshot_get_primary_key(kwargs)
777
+ if requested_primary_key is not None:
778
+ match_count = primary_keys.count(requested_primary_key)
779
+ if match_count == 1:
780
+ return self._build_manager(requested_primary_key)
781
+ if match_count > 1:
782
+ raise self._data.model.MultipleObjectsReturned
783
+ raise self._data.model.DoesNotExist
622
784
  element = self._data.get(**kwargs)
623
785
  return self._build_manager(element.pk)
624
786
 
@@ -643,8 +805,14 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
643
805
  search_date=self._search_date,
644
806
  sort_keys=self._sort_keys,
645
807
  sort_reverse=self._sort_reverse,
808
+ run_scoped_cacheable=self._run_scoped_cacheable,
646
809
  )
647
810
  self._track_effective_dependencies()
811
+ primary_keys = self._peek_run_scoped_primary_keys()
812
+ if primary_keys is not None:
813
+ if item < 0:
814
+ raise ValueError
815
+ return self._build_manager(primary_keys[item])
648
816
  return self._build_manager(self._data[item].pk)
649
817
 
650
818
  def __len__(self) -> int:
@@ -655,6 +823,9 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
655
823
  int: Size of the queryset.
656
824
  """
657
825
  self._track_effective_dependencies()
826
+ primary_keys = self._peek_run_scoped_primary_keys()
827
+ if primary_keys is not None:
828
+ return len(primary_keys)
658
829
  return self._data.count()
659
830
 
660
831
  def __str__(self) -> str:
@@ -694,6 +865,9 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
694
865
  pk = item.pk
695
866
  if pk is None:
696
867
  return False
868
+ primary_keys = self._peek_run_scoped_primary_keys()
869
+ if primary_keys is not None:
870
+ return pk in primary_keys
697
871
  return self._data.filter(pk=pk).exists()
698
872
 
699
873
  def sort(
@@ -779,6 +953,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
779
953
  search_date=self._search_date,
780
954
  sort_keys=key,
781
955
  sort_reverse=reverse,
956
+ run_scoped_cacheable=self._run_scoped_cacheable,
782
957
  )
783
958
 
784
959
  def none(self) -> DatabaseBucket[GeneralManagerType]:
@@ -28,6 +28,7 @@ from general_manager.cache.dependency_index import (
28
28
  )
29
29
  from general_manager.cache.dependency_publish import (
30
30
  CachePublishAborted,
31
+ PendingDependencyCachePublication,
31
32
  acquire_compute_lease,
32
33
  publish_dependency_cache_entry,
33
34
  release_compute_lease,
@@ -232,6 +233,7 @@ def cached(
232
233
  )
233
234
  lease = acquire_compute_lease(key)
234
235
 
236
+ lease_transferred_to_context = False
235
237
  try:
236
238
  cached_hit = read_dependency_cache_hit(
237
239
  cache_backend,
@@ -252,29 +254,47 @@ def cached(
252
254
  for entry_key, entry_dependencies in entries:
253
255
  record_fn(entry_key, set(entry_dependencies))
254
256
 
255
- try:
256
- publish_dependency_cache_entry(
257
- cache_key=key,
258
- result=result,
259
- dependencies=dependencies,
260
- cache_backend=cache_backend,
261
- timeout=timeout,
262
- started_generation=started_generation,
263
- record_many_fn=(
264
- None if record_fn is record_dependencies else record_many
265
- ),
266
- )
267
- except CachePublishAborted:
268
- logger.debug(
269
- "dependency cache publish aborted",
270
- context={
271
- "function": func.__qualname__,
272
- "key": key,
273
- "scope": scope,
274
- },
257
+ publish_context = current_calculation_run_context()
258
+ if publish_context is not None and record_fn is record_dependencies:
259
+ publish_context.buffer_dependency_cache_publication(
260
+ PendingDependencyCachePublication(
261
+ cache_key=key,
262
+ result=result,
263
+ dependencies=frozenset(dependencies),
264
+ cache_backend=cache_backend,
265
+ timeout=timeout,
266
+ started_generation=started_generation,
267
+ lease=lease,
268
+ )
275
269
  )
270
+ lease_transferred_to_context = True
271
+ else:
272
+ try:
273
+ publish_dependency_cache_entry(
274
+ cache_key=key,
275
+ result=result,
276
+ dependencies=dependencies,
277
+ cache_backend=cache_backend,
278
+ timeout=timeout,
279
+ started_generation=started_generation,
280
+ record_many_fn=(
281
+ None
282
+ if record_fn is record_dependencies
283
+ else record_many
284
+ ),
285
+ )
286
+ except CachePublishAborted:
287
+ logger.debug(
288
+ "dependency cache publish aborted",
289
+ context={
290
+ "function": func.__qualname__,
291
+ "key": key,
292
+ "scope": scope,
293
+ },
294
+ )
276
295
  finally:
277
- release_compute_lease(lease)
296
+ if not lease_transferred_to_context:
297
+ release_compute_lease(lease)
278
298
 
279
299
  logger.debug(
280
300
  "cache miss recorded",
@@ -45,6 +45,16 @@ class DependencyCacheGetManyBackend(DependencyCacheBackend, Protocol):
45
45
  ...
46
46
 
47
47
 
48
+ class DependencyCacheSetManyBackend(DependencyCacheBackend, Protocol):
49
+ def set_many(
50
+ self,
51
+ data: Mapping[str, Any],
52
+ timeout: int | None = None,
53
+ ) -> Any:
54
+ """Store cached values for many keys."""
55
+ ...
56
+
57
+
48
58
  def make_dependency_cache_entry(
49
59
  value: Any,
50
60
  dependencies: Iterable[Dependency],
@@ -124,6 +124,14 @@ def _set_dependency_data_change_count(count: int) -> int:
124
124
  return count
125
125
 
126
126
 
127
+ def _discard_active_context_dependency_cache_state() -> None:
128
+ from general_manager.cache.run_context import current_calculation_run_context
129
+
130
+ context = current_calculation_run_context()
131
+ if context is not None:
132
+ context.discard_dependency_cache_state()
133
+
134
+
127
135
  def begin_dependency_data_change() -> int:
128
136
  """
129
137
  Mark a data change as active and bump the dependency generation.
@@ -136,9 +144,17 @@ def begin_dependency_data_change() -> int:
136
144
  generation = _set_dependency_generation(get_dependency_generation() + 1)
137
145
  _set_dependency_data_change_count(_get_dependency_data_change_count() + 1)
138
146
  cache.set(DATA_CHANGE_LOCK_KEY, "1", None)
139
- return generation
140
147
  finally:
141
148
  release_lock()
149
+ try:
150
+ _discard_active_context_dependency_cache_state()
151
+ except Exception:
152
+ try:
153
+ end_dependency_data_change()
154
+ except Exception:
155
+ logger.exception("dependency data-change cleanup rollback failed")
156
+ raise
157
+ return generation
142
158
 
143
159
 
144
160
  def end_dependency_data_change() -> None:
@@ -4,13 +4,15 @@ from __future__ import annotations
4
4
 
5
5
  import time
6
6
  import uuid
7
+ from collections import defaultdict
7
8
  from dataclasses import dataclass
8
- from typing import Any, Callable, Iterable
9
+ from typing import Any, Callable, Iterable, TypeGuard
9
10
 
10
11
  from django.core.cache import cache as coordination_cache
11
12
 
12
13
  from general_manager.cache.dependency_cache import (
13
14
  DependencyCacheBackend,
15
+ DependencyCacheSetManyBackend,
14
16
  make_dependency_cache_entry,
15
17
  read_dependency_cache_hit,
16
18
  )
@@ -39,6 +41,19 @@ class CacheComputeLease:
39
41
  token: str
40
42
 
41
43
 
44
+ @dataclass(frozen=True)
45
+ class PendingDependencyCachePublication:
46
+ """A dependency-cache miss waiting for guarded publication."""
47
+
48
+ cache_key: str
49
+ result: Any
50
+ dependencies: frozenset[Dependency]
51
+ cache_backend: DependencyCacheBackend
52
+ timeout: int | None
53
+ started_generation: int
54
+ lease: CacheComputeLease
55
+
56
+
42
57
  RecordManyDependenciesFn = Callable[[Iterable[tuple[str, Iterable[Dependency]]]], None]
43
58
 
44
59
  COMPUTE_LOCK_PREFIX = "dependency_cache_compute_lock"
@@ -111,6 +126,81 @@ def _ensure_publish_current(started_generation: int) -> None:
111
126
  raise CachePublishAborted()
112
127
 
113
128
 
129
+ def _supports_set_many(
130
+ cache_backend: DependencyCacheBackend,
131
+ ) -> TypeGuard[DependencyCacheSetManyBackend]:
132
+ return callable(getattr(cache_backend, "set_many", None))
133
+
134
+
135
+ def _set_dependency_cache_entries(
136
+ entries: Iterable[PendingDependencyCachePublication],
137
+ ) -> None:
138
+ grouped: dict[
139
+ tuple[int, int | None],
140
+ list[PendingDependencyCachePublication],
141
+ ] = defaultdict(list)
142
+ for entry in entries:
143
+ grouped[(id(entry.cache_backend), entry.timeout)].append(entry)
144
+
145
+ for group_entries in grouped.values():
146
+ cache_backend = group_entries[0].cache_backend
147
+ timeout = group_entries[0].timeout
148
+ payloads = {
149
+ entry.cache_key: make_dependency_cache_entry(
150
+ entry.result,
151
+ entry.dependencies,
152
+ )
153
+ for entry in group_entries
154
+ }
155
+ if _supports_set_many(cache_backend):
156
+ failed_keys = cache_backend.set_many(payloads, timeout) or ()
157
+ for key in failed_keys:
158
+ if key in payloads:
159
+ cache_backend.set(key, payloads[key], timeout)
160
+ continue
161
+ for key, payload in payloads.items():
162
+ cache_backend.set(key, payload, timeout)
163
+
164
+
165
+ def publish_dependency_cache_entries(
166
+ entries: Iterable[PendingDependencyCachePublication],
167
+ ) -> None:
168
+ """Publish dependency metadata and values for current entries in one batch."""
169
+ pending_entries = tuple(entries)
170
+ if not pending_entries:
171
+ return
172
+
173
+ acquire_lock_with_retry("publish_dependency_cache_entries")
174
+ try:
175
+ if is_dependency_data_change_active():
176
+ raise CachePublishAborted()
177
+
178
+ current_generation = get_dependency_generation()
179
+ publishable_entries = tuple(
180
+ entry
181
+ for entry in pending_entries
182
+ if entry.started_generation == current_generation
183
+ )
184
+ if not publishable_entries:
185
+ return
186
+
187
+ idx = get_full_index()
188
+ for entry in publishable_entries:
189
+ if entry.dependencies:
190
+ _record_dependencies_locked(
191
+ idx,
192
+ entry.cache_key,
193
+ entry.dependencies,
194
+ )
195
+
196
+ _ensure_publish_current(current_generation)
197
+ set_full_index(idx)
198
+ _ensure_publish_current(current_generation)
199
+ _set_dependency_cache_entries(publishable_entries)
200
+ finally:
201
+ release_lock()
202
+
203
+
114
204
  def publish_dependency_cache_entry(
115
205
  *,
116
206
  cache_key: str,