GeneralManager 0.48.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.48.0/src/GeneralManager.egg-info → generalmanager-0.49.0}/PKG-INFO +1 -1
  2. {generalmanager-0.48.0 → generalmanager-0.49.0}/pyproject.toml +1 -1
  3. {generalmanager-0.48.0 → generalmanager-0.49.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/cache_decorator.py +41 -21
  5. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/dependency_cache.py +10 -0
  6. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/dependency_index.py +17 -1
  7. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/dependency_publish.py +91 -1
  8. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/run_context.py +98 -6
  9. {generalmanager-0.48.0 → generalmanager-0.49.0}/LICENSE +0 -0
  10. {generalmanager-0.48.0 → generalmanager-0.49.0}/README.md +0 -0
  11. {generalmanager-0.48.0 → generalmanager-0.49.0}/setup.cfg +0 -0
  12. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
  13. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  14. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/requires.txt +0 -0
  15. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
  16. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/__init__.py +0 -0
  17. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/__init__.py +0 -0
  18. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/api.py +0 -0
  19. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/bucket.py +0 -0
  20. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/cache.py +0 -0
  21. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/factory.py +0 -0
  22. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/general_manager.py +0 -0
  23. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/interface.py +0 -0
  24. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/manager.py +0 -0
  25. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/measurement.py +0 -0
  26. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/permission.py +0 -0
  27. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/rule.py +0 -0
  28. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/search.py +0 -0
  29. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/_types/utils.py +0 -0
  30. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/__init__.py +0 -0
  31. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql.py +0 -0
  32. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_errors.py +0 -0
  33. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_mutations.py +0 -0
  34. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_prefetch.py +0 -0
  35. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_resolvers.py +0 -0
  36. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_search.py +0 -0
  37. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  38. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_subscriptions.py +0 -0
  39. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/graphql_view.py +0 -0
  40. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/mutation.py +0 -0
  41. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/property.py +0 -0
  42. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/registry.py +0 -0
  43. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/remote_api.py +0 -0
  44. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/remote_invalidation.py +0 -0
  45. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
  46. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/apps.py +0 -0
  47. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bootstrap.py +0 -0
  48. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bucket/__init__.py +0 -0
  49. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bucket/base_bucket.py +0 -0
  50. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bucket/calculation_bucket.py +0 -0
  51. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bucket/database_bucket.py +0 -0
  52. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bucket/group_bucket.py +0 -0
  53. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/bucket/request_bucket.py +0 -0
  54. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/__init__.py +0 -0
  55. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/cache_tracker.py +0 -0
  56. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
  57. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/cache/signals.py +0 -0
  58. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/conf.py +0 -0
  59. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/factory/__init__.py +0 -0
  60. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/factory/auto_factory.py +0 -0
  61. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/factory/factories.py +0 -0
  62. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/factory/factory_methods.py +0 -0
  63. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/__init__.py +0 -0
  64. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/base_interface.py +0 -0
  65. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/__init__.py +0 -0
  66. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/calculation.py +0 -0
  67. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/database.py +0 -0
  68. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  69. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/bundles/request.py +0 -0
  70. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
  71. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/base.py +0 -0
  72. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
  73. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  74. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  75. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  76. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
  77. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  78. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  79. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  80. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  81. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  82. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  83. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/factory.py +0 -0
  84. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  85. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  86. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  87. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  88. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  89. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  90. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  91. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  92. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  93. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  94. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  95. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  96. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  97. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  98. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/registry.py +0 -0
  99. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  100. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  101. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  102. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  103. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  104. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
  105. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
  106. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/database.py +0 -0
  107. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  108. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
  109. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  110. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/interfaces/request.py +0 -0
  111. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/__init__.py +0 -0
  112. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  113. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  114. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
  115. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/orm_interface.py +0 -0
  116. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/requests.py +0 -0
  117. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/__init__.py +0 -0
  118. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  119. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/errors.py +0 -0
  120. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/interface/utils/models.py +0 -0
  121. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/logging.py +0 -0
  122. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/management/commands/search_index.py +0 -0
  123. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  124. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/management/commands/shell.py +0 -0
  125. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  126. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  127. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/manager/__init__.py +0 -0
  128. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/manager/general_manager.py +0 -0
  129. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/manager/group_manager.py +0 -0
  130. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/manager/input.py +0 -0
  131. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/manager/meta.py +0 -0
  132. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/measurement/__init__.py +0 -0
  133. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/measurement/measurement.py +0 -0
  134. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/measurement/measurement_field.py +0 -0
  135. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/metrics/__init__.py +0 -0
  136. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/metrics/graphql.py +0 -0
  137. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/migrations/0001_initial.py +0 -0
  138. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  139. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  140. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/migrations/__init__.py +0 -0
  141. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/models.py +0 -0
  142. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/__init__.py +0 -0
  143. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/audit.py +0 -0
  144. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/base_permission.py +0 -0
  145. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
  146. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/manager_based_permission.py +0 -0
  147. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/mutation_permission.py +0 -0
  148. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/permission_checks.py +0 -0
  149. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/permission_data_manager.py +0 -0
  150. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/permission/utils.py +0 -0
  151. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/public_api_registry.py +0 -0
  152. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/py.typed +0 -0
  153. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/rule/__init__.py +0 -0
  154. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/rule/handler.py +0 -0
  155. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/rule/rule.py +0 -0
  156. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/__init__.py +0 -0
  157. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/async_tasks.py +0 -0
  158. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backend.py +0 -0
  159. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backend_registry.py +0 -0
  160. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backends/__init__.py +0 -0
  161. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backends/dev.py +0 -0
  162. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backends/meilisearch.py +0 -0
  163. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backends/opensearch.py +0 -0
  164. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/backends/typesense.py +0 -0
  165. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/config.py +0 -0
  166. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/indexer.py +0 -0
  167. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/registry.py +0 -0
  168. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/search/utils.py +0 -0
  169. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/seeding/__init__.py +0 -0
  170. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/seeding/manager_landscape.py +0 -0
  171. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/__init__.py +0 -0
  172. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/args_to_kwargs.py +0 -0
  173. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/filter_parser.py +0 -0
  174. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/format_string.py +0 -0
  175. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/json_encoder.py +0 -0
  176. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/make_cache_key.py +0 -0
  177. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/none_to_zero.py +0 -0
  178. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/path_mapping.py +0 -0
  179. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/public_api.py +0 -0
  180. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/testing.py +0 -0
  181. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/utils/type_checks.py +0 -0
  182. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/__init__.py +0 -0
  183. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/actions.py +0 -0
  184. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/backend_registry.py +0 -0
  185. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/__init__.py +0 -0
  186. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/celery.py +0 -0
  187. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/local.py +0 -0
  188. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/backends/n8n.py +0 -0
  189. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/config.py +0 -0
  190. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/engine.py +0 -0
  191. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/event_registry.py +0 -0
  192. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/events.py +0 -0
  193. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/models.py +0 -0
  194. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/signal_bridge.py +0 -0
  195. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/tasks.py +0 -0
  196. {generalmanager-0.48.0 → generalmanager-0.49.0}/src/general_manager/workflow/telemetry.py +0 -0
  197. {generalmanager-0.48.0 → generalmanager-0.49.0}/tests/test_settings.py +0 -0
  198. {generalmanager-0.48.0 → generalmanager-0.49.0}/tests/test_urls.py +0 -0
  199. {generalmanager-0.48.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.48.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.48.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.48.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
@@ -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,
@@ -8,8 +8,13 @@ from contextvars import ContextVar, Token
8
8
  from types import TracebackType
9
9
  from typing import TYPE_CHECKING, Optional, TypeVar
10
10
 
11
+ from general_manager.logging import get_logger
12
+
11
13
  if TYPE_CHECKING:
12
14
  from general_manager.cache.dependency_cache import DependencyCacheHit
15
+ from general_manager.cache.dependency_publish import (
16
+ PendingDependencyCachePublication,
17
+ )
13
18
 
14
19
  K = TypeVar("K", bound=Hashable)
15
20
  T = TypeVar("T")
@@ -19,14 +24,27 @@ _active_context: ContextVar["CalculationRunContext | None"] = ContextVar(
19
24
  default=None,
20
25
  )
21
26
  ORM_BUCKET_RESULT_PREFIX = "orm_bucket_result"
27
+ DEFAULT_DEPENDENCY_CACHE_PUBLISH_BATCH_SIZE = 1000
28
+ logger = get_logger("cache.run_context")
22
29
 
23
30
 
24
31
  class CalculationRunContext:
25
32
  """Cache calculation work for one request, graph, bulk operation, or task."""
26
33
 
27
- def __init__(self) -> None:
34
+ def __init__(
35
+ self,
36
+ *,
37
+ dependency_cache_publish_batch_size: int = (
38
+ DEFAULT_DEPENDENCY_CACHE_PUBLISH_BATCH_SIZE
39
+ ),
40
+ ) -> None:
28
41
  self._values: dict[Hashable, object] = {}
29
42
  self._dependency_cache_hits: dict[str, DependencyCacheHit] = {}
43
+ self._dependency_cache_pending_publications: dict[
44
+ str,
45
+ PendingDependencyCachePublication,
46
+ ] = {}
47
+ self._dependency_cache_publish_batch_size = dependency_cache_publish_batch_size
30
48
  self._token: Token[CalculationRunContext | None] | None = None
31
49
 
32
50
  def __enter__(self) -> "CalculationRunContext":
@@ -39,11 +57,18 @@ class CalculationRunContext:
39
57
  exc_val: BaseException | None,
40
58
  exc_tb: TracebackType | None,
41
59
  ) -> None:
42
- if self._token is not None:
43
- _active_context.reset(self._token)
44
- self._token = None
45
- self._values.clear()
46
- self._dependency_cache_hits.clear()
60
+ try:
61
+ if exc_type is None:
62
+ self.flush_dependency_cache_publications()
63
+ else:
64
+ self.discard_dependency_cache_publications()
65
+ finally:
66
+ if self._token is not None:
67
+ _active_context.reset(self._token)
68
+ self._token = None
69
+ self._values.clear()
70
+ self._dependency_cache_hits.clear()
71
+ self._dependency_cache_pending_publications.clear()
47
72
 
48
73
  def get_or_set(self, key: Hashable, loader: Callable[[], T]) -> T:
49
74
  """Return a cached value for key, loading it once per active context."""
@@ -74,6 +99,73 @@ class CalculationRunContext:
74
99
  """Return a prefetched dependency-cache hit, or default when absent."""
75
100
  return self._dependency_cache_hits.get(key, default)
76
101
 
102
+ def buffer_dependency_cache_publication(
103
+ self,
104
+ entry: PendingDependencyCachePublication,
105
+ ) -> None:
106
+ """Buffer a dependency-cache miss for guarded batch publication."""
107
+ from general_manager.cache.dependency_cache import DependencyCacheHit
108
+ from general_manager.cache.dependency_publish import release_compute_lease
109
+
110
+ previous_entry = self._dependency_cache_pending_publications.get(
111
+ entry.cache_key
112
+ )
113
+ if previous_entry is not None and previous_entry.lease != entry.lease:
114
+ release_compute_lease(previous_entry.lease)
115
+ self._dependency_cache_pending_publications[entry.cache_key] = entry
116
+ self._dependency_cache_hits[entry.cache_key] = DependencyCacheHit(
117
+ value=entry.result,
118
+ dependencies=entry.dependencies,
119
+ )
120
+ if (
121
+ len(self._dependency_cache_pending_publications)
122
+ >= self._dependency_cache_publish_batch_size
123
+ ):
124
+ self.flush_dependency_cache_publications()
125
+
126
+ def flush_dependency_cache_publications(self) -> None:
127
+ """Publish buffered dependency-cache misses and release their leases."""
128
+ entries = tuple(self._dependency_cache_pending_publications.values())
129
+ if not entries:
130
+ return
131
+ self._dependency_cache_pending_publications.clear()
132
+
133
+ from general_manager.cache.dependency_publish import (
134
+ CachePublishAborted,
135
+ publish_dependency_cache_entries,
136
+ release_compute_lease,
137
+ )
138
+
139
+ try:
140
+ publish_dependency_cache_entries(entries)
141
+ except CachePublishAborted:
142
+ logger.debug(
143
+ "dependency cache batch publish aborted",
144
+ context={"entry_count": len(entries)},
145
+ )
146
+ finally:
147
+ for entry in entries:
148
+ release_compute_lease(entry.lease)
149
+
150
+ def discard_dependency_cache_publications(self) -> None:
151
+ """Drop buffered dependency-cache misses and release their leases."""
152
+ entries = tuple(self._dependency_cache_pending_publications.values())
153
+ if not entries:
154
+ return
155
+ self._dependency_cache_pending_publications.clear()
156
+
157
+ from general_manager.cache.dependency_publish import release_compute_lease
158
+
159
+ for entry in entries:
160
+ release_compute_lease(entry.lease)
161
+
162
+ def discard_dependency_cache_state(self) -> None:
163
+ """Drop dependency-cache hits and buffered publications for this run."""
164
+ try:
165
+ self.discard_dependency_cache_publications()
166
+ finally:
167
+ self._dependency_cache_hits.clear()
168
+
77
169
  def discard_prefix(self, prefix: tuple[Hashable, ...]) -> None:
78
170
  """Discard tuple keys that start with the supplied prefix."""
79
171
  for key in list(self._values):
File without changes