GeneralManager 0.37.2__tar.gz → 0.37.3__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 (189) hide show
  1. {generalmanager-0.37.2/src/GeneralManager.egg-info → generalmanager-0.37.3}/PKG-INFO +1 -1
  2. {generalmanager-0.37.2 → generalmanager-0.37.3}/pyproject.toml +1 -1
  3. {generalmanager-0.37.2 → generalmanager-0.37.3/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/GeneralManager.egg-info/SOURCES.txt +1 -0
  5. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql.py +5 -4
  6. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_mutations.py +39 -1
  7. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_resolvers.py +3 -2
  8. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_search.py +11 -8
  9. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +41 -4
  10. generalmanager-0.37.3/src/general_manager/utils/type_checks.py +8 -0
  11. {generalmanager-0.37.2 → generalmanager-0.37.3}/LICENSE +0 -0
  12. {generalmanager-0.37.2 → generalmanager-0.37.3}/README.md +0 -0
  13. {generalmanager-0.37.2 → generalmanager-0.37.3}/setup.cfg +0 -0
  14. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  15. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/GeneralManager.egg-info/requires.txt +0 -0
  16. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/GeneralManager.egg-info/top_level.txt +0 -0
  17. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/__init__.py +0 -0
  18. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/__init__.py +0 -0
  19. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/api.py +0 -0
  20. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/bucket.py +0 -0
  21. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/cache.py +0 -0
  22. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/factory.py +0 -0
  23. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/general_manager.py +0 -0
  24. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/interface.py +0 -0
  25. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/manager.py +0 -0
  26. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/measurement.py +0 -0
  27. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/permission.py +0 -0
  28. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/rule.py +0 -0
  29. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/_types/utils.py +0 -0
  30. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/__init__.py +0 -0
  31. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_errors.py +0 -0
  32. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  33. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_subscriptions.py +0 -0
  34. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/graphql_view.py +0 -0
  35. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/mutation.py +0 -0
  36. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/property.py +0 -0
  37. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/registry.py +0 -0
  38. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/remote_api.py +0 -0
  39. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/remote_invalidation.py +0 -0
  40. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/api/remote_invalidation_client.py +0 -0
  41. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/apps.py +0 -0
  42. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bootstrap.py +0 -0
  43. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bucket/__init__.py +0 -0
  44. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bucket/base_bucket.py +0 -0
  45. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bucket/calculation_bucket.py +0 -0
  46. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bucket/database_bucket.py +0 -0
  47. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bucket/group_bucket.py +0 -0
  48. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/bucket/request_bucket.py +0 -0
  49. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/cache/__init__.py +0 -0
  50. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/cache/cache_decorator.py +0 -0
  51. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/cache/cache_tracker.py +0 -0
  52. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/cache/dependency_index.py +0 -0
  53. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/cache/model_dependency_collector.py +0 -0
  54. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/cache/signals.py +0 -0
  55. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/conf.py +0 -0
  56. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/factory/__init__.py +0 -0
  57. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/factory/auto_factory.py +0 -0
  58. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/factory/factories.py +0 -0
  59. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/factory/factory_methods.py +0 -0
  60. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/__init__.py +0 -0
  61. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/base_interface.py +0 -0
  62. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/bundles/__init__.py +0 -0
  63. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/bundles/calculation.py +0 -0
  64. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/bundles/database.py +0 -0
  65. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  66. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/bundles/request.py +0 -0
  67. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/__init__.py +0 -0
  68. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/base.py +0 -0
  69. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/builtin.py +0 -0
  70. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  71. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  72. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  73. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/configuration.py +0 -0
  74. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  75. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  76. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  77. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  78. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  79. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  80. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/factory.py +0 -0
  81. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  82. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  83. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  84. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  85. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  86. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  87. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  88. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  89. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  90. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  91. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  92. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  93. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  94. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/registry.py +0 -0
  95. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  96. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  97. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  98. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  99. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/__init__.py +0 -0
  100. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/calculation.py +0 -0
  101. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/database.py +0 -0
  102. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  103. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/read_only.py +0 -0
  104. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  105. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/interfaces/request.py +0 -0
  106. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/manifests/__init__.py +0 -0
  107. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  108. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  109. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/manifests/capability_models.py +0 -0
  110. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/orm_interface.py +0 -0
  111. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/requests.py +0 -0
  112. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/utils/__init__.py +0 -0
  113. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  114. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/utils/errors.py +0 -0
  115. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/interface/utils/models.py +0 -0
  116. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/logging.py +0 -0
  117. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/management/commands/search_index.py +0 -0
  118. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/management/commands/shell.py +0 -0
  119. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  120. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  121. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/manager/__init__.py +0 -0
  122. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/manager/general_manager.py +0 -0
  123. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/manager/group_manager.py +0 -0
  124. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/manager/input.py +0 -0
  125. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/manager/meta.py +0 -0
  126. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/measurement/__init__.py +0 -0
  127. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/measurement/measurement.py +0 -0
  128. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/measurement/measurement_field.py +0 -0
  129. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/metrics/__init__.py +0 -0
  130. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/metrics/graphql.py +0 -0
  131. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/migrations/0001_initial.py +0 -0
  132. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  133. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  134. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/migrations/__init__.py +0 -0
  135. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/models.py +0 -0
  136. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/__init__.py +0 -0
  137. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/audit.py +0 -0
  138. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/base_permission.py +0 -0
  139. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/manager_based_permission.py +0 -0
  140. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/mutation_permission.py +0 -0
  141. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/permission_checks.py +0 -0
  142. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/permission_data_manager.py +0 -0
  143. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/permission/utils.py +0 -0
  144. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/public_api_registry.py +0 -0
  145. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/py.typed +0 -0
  146. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/rule/__init__.py +0 -0
  147. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/rule/handler.py +0 -0
  148. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/rule/rule.py +0 -0
  149. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/__init__.py +0 -0
  150. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/async_tasks.py +0 -0
  151. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backend.py +0 -0
  152. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backend_registry.py +0 -0
  153. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backends/__init__.py +0 -0
  154. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backends/dev.py +0 -0
  155. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backends/meilisearch.py +0 -0
  156. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backends/opensearch.py +0 -0
  157. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/backends/typesense.py +0 -0
  158. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/config.py +0 -0
  159. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/indexer.py +0 -0
  160. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/registry.py +0 -0
  161. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/search/utils.py +0 -0
  162. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/__init__.py +0 -0
  163. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/args_to_kwargs.py +0 -0
  164. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/filter_parser.py +0 -0
  165. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/format_string.py +0 -0
  166. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/json_encoder.py +0 -0
  167. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/make_cache_key.py +0 -0
  168. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/none_to_zero.py +0 -0
  169. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/path_mapping.py +0 -0
  170. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/public_api.py +0 -0
  171. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/utils/testing.py +0 -0
  172. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/__init__.py +0 -0
  173. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/actions.py +0 -0
  174. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/backend_registry.py +0 -0
  175. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/backends/__init__.py +0 -0
  176. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/backends/celery.py +0 -0
  177. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/backends/local.py +0 -0
  178. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/backends/n8n.py +0 -0
  179. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/config.py +0 -0
  180. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/engine.py +0 -0
  181. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/event_registry.py +0 -0
  182. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/events.py +0 -0
  183. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/models.py +0 -0
  184. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/signal_bridge.py +0 -0
  185. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/tasks.py +0 -0
  186. {generalmanager-0.37.2 → generalmanager-0.37.3}/src/general_manager/workflow/telemetry.py +0 -0
  187. {generalmanager-0.37.2 → generalmanager-0.37.3}/tests/test_settings.py +0 -0
  188. {generalmanager-0.37.2 → generalmanager-0.37.3}/tests/test_urls.py +0 -0
  189. {generalmanager-0.37.2 → generalmanager-0.37.3}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.37.2
3
+ Version: 0.37.3
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.37.2"
7
+ version = "0.37.3"
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.37.2
3
+ Version: 0.37.3
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
@@ -166,6 +166,7 @@ src/general_manager/utils/none_to_zero.py
166
166
  src/general_manager/utils/path_mapping.py
167
167
  src/general_manager/utils/public_api.py
168
168
  src/general_manager/utils/testing.py
169
+ src/general_manager/utils/type_checks.py
169
170
  src/general_manager/workflow/__init__.py
170
171
  src/general_manager/workflow/actions.py
171
172
  src/general_manager/workflow/backend_registry.py
@@ -39,6 +39,7 @@ from general_manager.interface.base_interface import InterfaceBase
39
39
  from general_manager.logging import get_logger
40
40
  from general_manager.manager.general_manager import GeneralManager
41
41
  from general_manager.measurement.measurement import Measurement
42
+ from general_manager.utils.type_checks import safe_issubclass
42
43
 
43
44
  from graphql import GraphQLError
44
45
 
@@ -404,7 +405,7 @@ class GraphQL:
404
405
  field_info,
405
406
  ) in generalManagerClass.Interface.get_attribute_types().items():
406
407
  field_type = field_info["type"]
407
- if issubclass(field_type, GeneralManager):
408
+ if safe_issubclass(field_type, GeneralManager):
408
409
  continue
409
410
  else:
410
411
  sort_options.append(field_name)
@@ -546,9 +547,9 @@ class GraphQL:
546
547
  Returns:
547
548
  Any: Graphene field or type configured for the attribute.
548
549
  """
549
- if issubclass(field_type, Measurement):
550
+ if safe_issubclass(field_type, Measurement):
550
551
  return graphene.Field(MeasurementType, target_unit=graphene.String())
551
- elif issubclass(field_type, GeneralManager):
552
+ elif safe_issubclass(field_type, GeneralManager):
552
553
  if field_name.endswith("_list"):
553
554
  attributes: dict[str, Any] = {
554
555
  "reverse": graphene.Boolean(),
@@ -714,7 +715,7 @@ class GraphQL:
714
715
  input_field_name,
715
716
  input_field,
716
717
  ) in generalManagerClass.Interface.input_fields.items():
717
- if issubclass(input_field.type, GeneralManager):
718
+ if safe_issubclass(input_field.type, GeneralManager):
718
719
  key = f"{input_field_name}_id"
719
720
  identification_fields[key] = graphene.Argument(
720
721
  graphene.ID, required=input_field.required
@@ -19,6 +19,7 @@ from django.db.models import NOT_PROVIDED
19
19
 
20
20
  from general_manager.interface.base_interface import InterfaceBase
21
21
  from general_manager.manager.general_manager import GeneralManager
22
+ from general_manager.utils.type_checks import safe_issubclass
22
23
  from general_manager.api.graphql_errors import (
23
24
  HANDLED_MANAGER_ERRORS,
24
25
  MissingManagerIdentifierError,
@@ -30,6 +31,36 @@ if TYPE_CHECKING:
30
31
  from graphene import ResolveInfo as GraphQLResolveInfo
31
32
 
32
33
 
34
+ def _normalize_mutation_kwargs_for_manager(
35
+ general_manager_class: type[GeneralManager],
36
+ kwargs: dict[str, Any],
37
+ ) -> dict[str, Any]:
38
+ """Normalize GraphQL relation aliases to the ORM mutation contract."""
39
+ interface_cls = getattr(general_manager_class, "Interface", None)
40
+ if interface_cls is None:
41
+ return dict(kwargs)
42
+
43
+ attribute_types = interface_cls.get_attribute_types()
44
+ normalized = dict(kwargs)
45
+
46
+ for key in list(kwargs.keys()):
47
+ if key.endswith("_list") and not key.endswith("_id_list"):
48
+ base_key = key.removesuffix("_list")
49
+ if base_key in attribute_types:
50
+ normalized.setdefault(f"{base_key}_id_list", normalized[key])
51
+ normalized.pop(key, None)
52
+ continue
53
+
54
+ if key.startswith("_") and not key.endswith("_id"):
55
+ type_info = attribute_types.get(key)
56
+ relation_type = type_info["type"] if type_info is not None else None
57
+ if safe_issubclass(relation_type, GeneralManager):
58
+ normalized.setdefault(f"{key}_id", normalized[key])
59
+ normalized.pop(key, None)
60
+
61
+ return normalized
62
+
63
+
33
64
  # ---------------------------------------------------------------------------
34
65
  # Write-field helpers
35
66
  # ---------------------------------------------------------------------------
@@ -64,7 +95,7 @@ def create_write_fields(interface_cls: InterfaceBase) -> dict[str, Any]:
64
95
  default = info["default"]
65
96
 
66
97
  fld: Any
67
- if issubclass(typ, GeneralManager):
98
+ if safe_issubclass(typ, GeneralManager):
68
99
  if name.endswith("_list"):
69
100
  fld = graphene.List(graphene.ID, required=req, default_value=default)
70
101
  else:
@@ -125,6 +156,7 @@ def generate_create_mutation_class(
125
156
  for field_name, value in kwargs.items()
126
157
  if value is not NOT_PROVIDED
127
158
  }
159
+ kwargs = _normalize_mutation_kwargs_for_manager(generalManagerClass, kwargs)
128
160
  instance = generalManagerClass.create(
129
161
  **kwargs, creator_id=info.context.user.id
130
162
  )
@@ -184,6 +216,12 @@ def generate_update_mutation_class(
184
216
  if manager_id is None:
185
217
  raise handle_graph_ql_error(MissingManagerIdentifierError())
186
218
  try:
219
+ kwargs = {
220
+ field_name: value
221
+ for field_name, value in kwargs.items()
222
+ if value is not NOT_PROVIDED
223
+ }
224
+ kwargs = _normalize_mutation_kwargs_for_manager(generalManagerClass, kwargs)
187
225
  instance = generalManagerClass(id=manager_id).update(
188
226
  creator_id=info.context.user.id, **kwargs
189
227
  )
@@ -20,6 +20,7 @@ from general_manager.bucket.base_bucket import Bucket
20
20
  from general_manager.manager.general_manager import GeneralManager
21
21
  from general_manager.measurement.measurement import Measurement
22
22
  from general_manager.api.graphql_errors import get_read_permission_filter
23
+ from general_manager.utils.type_checks import safe_issubclass
23
24
 
24
25
  if TYPE_CHECKING:
25
26
  from graphene import ResolveInfo as GraphQLResolveInfo
@@ -505,10 +506,10 @@ def create_resolver(field_name: str, field_type: type) -> Callable[..., Any]:
505
506
  :class:`~general_manager.measurement.Measurement` fields, and
506
507
  :func:`create_normal_resolver` for everything else.
507
508
  """
508
- if field_name.endswith("_list") and issubclass(field_type, GeneralManager):
509
+ if field_name.endswith("_list") and safe_issubclass(field_type, GeneralManager):
509
510
  return create_list_resolver(
510
511
  lambda self, _include_inactive: getattr(self, field_name), field_type
511
512
  )
512
- if issubclass(field_type, Measurement):
513
+ if safe_issubclass(field_type, Measurement):
513
514
  return create_measurement_resolver(field_name)
514
515
  return create_normal_resolver(field_name)
@@ -31,6 +31,7 @@ from django.utils import timezone
31
31
  from general_manager.logging import get_logger
32
32
  from general_manager.manager.general_manager import GeneralManager
33
33
  from general_manager.measurement.measurement import Measurement
34
+ from general_manager.utils.type_checks import safe_issubclass
34
35
  from general_manager.search.backend_registry import get_search_backend
35
36
  from general_manager.search.registry import (
36
37
  get_search_config,
@@ -318,28 +319,30 @@ def get_filter_options(
318
319
  "endswith",
319
320
  ]
320
321
 
321
- if issubclass(attribute_type, GeneralManager):
322
+ normalized_type = attribute_type if isinstance(attribute_type, type) else str
323
+
324
+ if safe_issubclass(normalized_type, GeneralManager):
322
325
  yield attribute_name, None
323
- elif issubclass(attribute_type, Measurement):
326
+ elif safe_issubclass(normalized_type, Measurement):
324
327
  yield attribute_name, MeasurementScalar()
325
328
  for option in number_options:
326
329
  yield f"{attribute_name}__{option}", MeasurementScalar()
327
330
  else:
328
331
  yield (
329
332
  attribute_name,
330
- map_field_to_graphene_read(attribute_type, attribute_name, attr_info),
333
+ map_field_to_graphene_read(normalized_type, attribute_name, attr_info),
331
334
  )
332
- if issubclass(attribute_type, (int, float, Decimal, date, datetime)):
335
+ if safe_issubclass(normalized_type, (int, float, Decimal, date, datetime)):
333
336
  for option in number_options:
334
337
  yield (
335
338
  f"{attribute_name}__{option}",
336
339
  map_field_to_graphene_read(
337
- attribute_type, attribute_name, attr_info
340
+ normalized_type, attribute_name, attr_info
338
341
  ),
339
342
  )
340
- elif issubclass(attribute_type, str):
343
+ elif safe_issubclass(normalized_type, str):
341
344
  base_type = map_field_to_graphene_base_type(
342
- attribute_type,
345
+ normalized_type,
343
346
  attr_info.get("graphql_scalar") if attr_info else None,
344
347
  )
345
348
  for option in string_options:
@@ -349,7 +352,7 @@ def get_filter_options(
349
352
  yield (
350
353
  f"{attribute_name}__{option}",
351
354
  map_field_to_graphene_read(
352
- attribute_type, attribute_name, attr_info
355
+ normalized_type, attribute_name, attr_info
353
356
  ),
354
357
  )
355
358
 
@@ -23,6 +23,11 @@ class PayloadNormalizer:
23
23
  self._attributes = set(vars(model).keys())
24
24
  self._field_names = {field.name for field in model._meta.get_fields()}
25
25
  self._many_to_many_fields = {field.name for field in model._meta.many_to_many}
26
+ self._relation_fields = {
27
+ field.name
28
+ for field in model._meta.get_fields()
29
+ if isinstance(field, (models.ForeignKey, models.OneToOneField))
30
+ }
26
31
 
27
32
  # region filter/exclude helpers
28
33
  def normalize_filter_kwargs(self, kwargs: dict[str, Any]) -> dict[str, Any]:
@@ -51,8 +56,11 @@ class PayloadNormalizer:
51
56
  UnknownFieldError: If any key's base name is not an attribute of the model instance and not a model field name.
52
57
  """
53
58
  for key in kwargs:
54
- base_key = key.split("_id_list")[0]
55
- if base_key not in self._attributes and base_key not in self._field_names:
59
+ candidate_key = self._key_for_validation(key)
60
+ if (
61
+ candidate_key not in self._attributes
62
+ and candidate_key not in self._field_names
63
+ ):
56
64
  raise UnknownFieldError(key, self.model.__name__)
57
65
 
58
66
  def split_many_to_many(
@@ -72,9 +80,9 @@ class PayloadNormalizer:
72
80
  """
73
81
  many_kwargs: dict[str, Any] = {}
74
82
  for key, _value in list(kwargs.items()):
75
- base_key = key.split("_id_list")[0]
83
+ base_key = self._m2m_alias_base_key(key)
76
84
  if base_key in self._many_to_many_fields:
77
- many_kwargs[key] = kwargs.pop(key)
85
+ many_kwargs[f"{base_key}_id_list"] = kwargs.pop(key)
78
86
  return kwargs, many_kwargs
79
87
 
80
88
  def normalize_simple_values(self, kwargs: dict[str, Any]) -> dict[str, Any]:
@@ -99,6 +107,13 @@ class PayloadNormalizer:
99
107
  normalized_value = manager_value
100
108
  elif manager_value is not None:
101
109
  normalized_value = manager_value
110
+ elif (
111
+ key in self._relation_fields
112
+ and not key.endswith("_id")
113
+ and not isinstance(value, models.Model)
114
+ and value is not None
115
+ ):
116
+ normalized_key = f"{key}_id"
102
117
  normalized[normalized_key] = normalized_value
103
118
  return normalized
104
119
 
@@ -133,6 +148,15 @@ class PayloadNormalizer:
133
148
 
134
149
  # endregion
135
150
 
151
+ def _key_for_validation(self, key: str) -> str:
152
+ """Resolve relation list aliases only when they target real M2M fields."""
153
+ base_key = self._m2m_alias_base_key(key)
154
+ return base_key if base_key in self._many_to_many_fields else key
155
+
156
+ def _m2m_alias_base_key(self, key: str) -> str:
157
+ """Return the base key for M2M alias forms, or the original key."""
158
+ return _base_field_name(key)
159
+
136
160
  @staticmethod
137
161
  def _unwrap_manager(value: Any) -> Any:
138
162
  """
@@ -200,3 +224,16 @@ def _general_manager_base() -> type | None:
200
224
  except ImportError: # pragma: no cover - defensive
201
225
  return None
202
226
  return GeneralManager
227
+
228
+
229
+ def _base_field_name(key: str) -> str:
230
+ """
231
+ Normalize payload key suffixes used for relation list fields.
232
+
233
+ Accepts both canonical (`*_id_list`) and GraphQL-facing (`*_list`) spellings.
234
+ """
235
+ if key.endswith("_id_list"):
236
+ return key[: -len("_id_list")]
237
+ if key.endswith("_list"):
238
+ return key[: -len("_list")]
239
+ return key
@@ -0,0 +1,8 @@
1
+ """Type-checking helpers shared across the codebase."""
2
+
3
+ from __future__ import annotations
4
+
5
+
6
+ def safe_issubclass(candidate: object, parent: type | tuple[type, ...]) -> bool:
7
+ """Return True when *candidate* is a class and a subclass of *parent*."""
8
+ return isinstance(candidate, type) and issubclass(candidate, parent)
File without changes