GeneralManager 0.85.0__tar.gz → 0.86.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 (342) hide show
  1. {generalmanager-0.85.0/src/GeneralManager.egg-info → generalmanager-0.86.0}/PKG-INFO +1 -1
  2. {generalmanager-0.85.0 → generalmanager-0.86.0}/pyproject.toml +1 -1
  3. {generalmanager-0.85.0 → generalmanager-0.86.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
  4. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql.py +44 -3
  5. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_identifiers.py +22 -3
  6. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_resolvers.py +13 -3
  7. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_search.py +4 -0
  8. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_subscriptions.py +8 -3
  9. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/mutation.py +5 -0
  10. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bootstrap.py +5 -1
  11. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/calculation_bucket.py +117 -16
  12. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/base_interface.py +31 -1
  13. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/calculation/input_resolution.py +11 -3
  14. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/manager/general_manager.py +25 -2
  15. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/manager/input.py +152 -2
  16. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/manager/meta.py +10 -0
  17. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/filter_parser.py +61 -7
  18. {generalmanager-0.85.0 → generalmanager-0.86.0}/LICENSE +0 -0
  19. {generalmanager-0.85.0 → generalmanager-0.86.0}/README.md +0 -0
  20. {generalmanager-0.85.0 → generalmanager-0.86.0}/setup.cfg +0 -0
  21. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
  22. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
  23. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/GeneralManager.egg-info/requires.txt +0 -0
  24. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
  25. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/__init__.py +0 -0
  26. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/__init__.py +0 -0
  27. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/api.py +0 -0
  28. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/bucket.py +0 -0
  29. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/cache.py +0 -0
  30. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/dataframes.py +0 -0
  31. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/factory.py +0 -0
  32. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/general_manager.py +0 -0
  33. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/interface.py +0 -0
  34. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/manager.py +0 -0
  35. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/measurement.py +0 -0
  36. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/permission.py +0 -0
  37. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/rule.py +0 -0
  38. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/search.py +0 -0
  39. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/_types/utils.py +0 -0
  40. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/__init__.py +0 -0
  41. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_as_of.py +0 -0
  42. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_errors.py +0 -0
  43. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_groups.py +0 -0
  44. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_mutations.py +0 -0
  45. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_ordering.py +0 -0
  46. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_output.py +0 -0
  47. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_prefetch.py +0 -0
  48. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_relations.py +0 -0
  49. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
  50. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_type.py +0 -0
  51. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_view.py +0 -0
  52. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_warmup.py +0 -0
  53. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_warmup_registry.py +0 -0
  54. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
  55. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/notification_batching.py +0 -0
  56. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/property.py +0 -0
  57. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/registry.py +0 -0
  58. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/remote_api.py +0 -0
  59. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/remote_invalidation.py +0 -0
  60. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
  61. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/apps.py +0 -0
  62. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/as_of.py +0 -0
  63. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/__init__.py +0 -0
  64. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/_materialized_bucket.py +0 -0
  65. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/_ordering.py +0 -0
  66. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/base_bucket.py +0 -0
  67. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/database_bucket.py +0 -0
  68. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/excel_bucket.py +0 -0
  69. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/group_bucket.py +0 -0
  70. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/indexing.py +0 -0
  71. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/projection.py +0 -0
  72. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/bucket/request_bucket.py +0 -0
  73. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/__init__.py +0 -0
  74. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/_dependency_graph.py +0 -0
  75. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/batch_refresh.py +0 -0
  76. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/cache_decorator.py +0 -0
  77. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/cache_tracker.py +0 -0
  78. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/data_change_context.py +0 -0
  79. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/dependency_cache.py +0 -0
  80. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/dependency_index.py +0 -0
  81. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/dependency_matching.py +0 -0
  82. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/dependency_publish.py +0 -0
  83. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/dependency_shards.py +0 -0
  84. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
  85. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/run_context.py +0 -0
  86. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/run_context_lru.py +0 -0
  87. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/signals.py +0 -0
  88. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/cache/transaction_barrier.py +0 -0
  89. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/__init__.py +0 -0
  90. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/audit.py +0 -0
  91. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/bootstrap.py +0 -0
  92. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/checks.py +0 -0
  93. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/consumer.py +0 -0
  94. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/context.py +0 -0
  95. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/errors.py +0 -0
  96. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/__init__.py +0 -0
  97. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/__main__.py +0 -0
  98. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/baseline.py +0 -0
  99. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
  100. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
  101. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
  102. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
  103. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
  104. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
  105. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
  106. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/diagnostics.py +0 -0
  107. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/fingerprints.py +0 -0
  108. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/fixtures.py +0 -0
  109. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/judges/__init__.py +0 -0
  110. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
  111. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/judges/contract.py +0 -0
  112. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
  113. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
  114. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/readiness.py +0 -0
  115. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/runner.py +0 -0
  116. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/evals/traces.py +0 -0
  117. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/grounding.py +0 -0
  118. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/models.py +0 -0
  119. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/__init__.py +0 -0
  120. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/budget.py +0 -0
  121. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/calculations.py +0 -0
  122. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/catalog.py +0 -0
  123. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/config.py +0 -0
  124. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/events.py +0 -0
  125. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/evidence.py +0 -0
  126. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/models.py +0 -0
  127. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/planner.py +0 -0
  128. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/provider_calls.py +0 -0
  129. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/resolver.py +0 -0
  130. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/routing.py +0 -0
  131. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/scheduler.py +0 -0
  132. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/synthesis.py +0 -0
  133. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/planned/validation.py +0 -0
  134. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/__init__.py +0 -0
  135. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/_shared.py +0 -0
  136. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/anthropic.py +0 -0
  137. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/base.py +0 -0
  138. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/google.py +0 -0
  139. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/ollama.py +0 -0
  140. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/providers/openai.py +0 -0
  141. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/rate_limits.py +0 -0
  142. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/routing.py +0 -0
  143. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/schema_index.py +0 -0
  144. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/settings.py +0 -0
  145. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/signals.py +0 -0
  146. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/system_prompt.py +0 -0
  147. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/tool_metadata.py +0 -0
  148. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/tools.py +0 -0
  149. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/turns.py +0 -0
  150. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/chat/views.py +0 -0
  151. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/conf.py +0 -0
  152. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/dataframes/__init__.py +0 -0
  153. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/dataframes/measurements.py +0 -0
  154. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/factory/__init__.py +0 -0
  155. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/factory/auto_factory.py +0 -0
  156. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/factory/factories.py +0 -0
  157. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/factory/factory_methods.py +0 -0
  158. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/__init__.py +0 -0
  159. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/bundles/__init__.py +0 -0
  160. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/bundles/calculation.py +0 -0
  161. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/bundles/database.py +0 -0
  162. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/bundles/excel.py +0 -0
  163. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
  164. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/bundles/request.py +0 -0
  165. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
  166. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/base.py +0 -0
  167. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
  168. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
  169. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
  170. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
  171. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
  172. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
  173. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
  174. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
  175. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
  176. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
  177. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
  178. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
  179. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/factory.py +0 -0
  180. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
  181. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
  182. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
  183. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/create_many.py +0 -0
  184. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
  185. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
  186. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
  187. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
  188. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
  189. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
  190. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
  191. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
  192. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
  193. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
  194. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
  195. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
  196. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
  197. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
  198. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/registry.py +0 -0
  199. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
  200. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
  201. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/excel.py +0 -0
  202. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/excel_store.py +0 -0
  203. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/excel_workbook.py +0 -0
  204. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
  205. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
  206. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
  207. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
  208. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
  209. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/database.py +0 -0
  210. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/excel.py +0 -0
  211. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
  212. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
  213. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
  214. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/interfaces/request.py +0 -0
  215. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/manifests/__init__.py +0 -0
  216. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
  217. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
  218. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
  219. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/orm_interface.py +0 -0
  220. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/requests.py +0 -0
  221. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/utils/__init__.py +0 -0
  222. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
  223. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/utils/errors.py +0 -0
  224. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/utils/history.py +0 -0
  225. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/interface/utils/models.py +0 -0
  226. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/logging.py +0 -0
  227. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/chat_cleanup.py +0 -0
  228. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
  229. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/graphql_warmup.py +0 -0
  230. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
  231. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/search_index.py +0 -0
  232. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/search_reconcile.py +0 -0
  233. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
  234. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/shell.py +0 -0
  235. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/sync_read_only.py +0 -0
  236. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
  237. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
  238. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/manager/__init__.py +0 -0
  239. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/manager/bulk_create.py +0 -0
  240. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/manager/group_manager.py +0 -0
  241. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/measurement/__init__.py +0 -0
  242. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/measurement/measurement.py +0 -0
  243. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/measurement/measurement_field.py +0 -0
  244. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/metrics/__init__.py +0 -0
  245. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/metrics/graphql.py +0 -0
  246. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0001_initial.py +0 -0
  247. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
  248. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
  249. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
  250. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0004_search_index_state.py +0 -0
  251. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
  252. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
  253. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0007_upload_intent.py +0 -0
  254. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
  255. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
  256. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
  257. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
  258. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
  259. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/migrations/__init__.py +0 -0
  260. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/models.py +0 -0
  261. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/__init__.py +0 -0
  262. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/audit.py +0 -0
  263. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/base_permission.py +0 -0
  264. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
  265. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/manager_based_permission.py +0 -0
  266. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/mutation_permission.py +0 -0
  267. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/permission_checks.py +0 -0
  268. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/permission_data_manager.py +0 -0
  269. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/permission/utils.py +0 -0
  270. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/public_api_registry.py +0 -0
  271. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/py.typed +0 -0
  272. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/rule/__init__.py +0 -0
  273. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/rule/handler.py +0 -0
  274. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/rule/rule.py +0 -0
  275. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/__init__.py +0 -0
  276. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/async_tasks.py +0 -0
  277. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backend.py +0 -0
  278. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backend_registry.py +0 -0
  279. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backends/__init__.py +0 -0
  280. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backends/dev.py +0 -0
  281. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backends/meilisearch.py +0 -0
  282. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backends/opensearch.py +0 -0
  283. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/backends/typesense.py +0 -0
  284. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/checks.py +0 -0
  285. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/config.py +0 -0
  286. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/identity.py +0 -0
  287. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/indexer.py +0 -0
  288. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/invalidation.py +0 -0
  289. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/m2m_invalidation.py +0 -0
  290. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/models.py +0 -0
  291. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/reconciliation.py +0 -0
  292. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/registry.py +0 -0
  293. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/tasks.py +0 -0
  294. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/search/utils.py +0 -0
  295. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/seeding/__init__.py +0 -0
  296. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/seeding/manager_landscape.py +0 -0
  297. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/__init__.py +0 -0
  298. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/adapters.py +0 -0
  299. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/checks.py +0 -0
  300. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/config.py +0 -0
  301. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/errors.py +0 -0
  302. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/finalization.py +0 -0
  303. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/graphql.py +0 -0
  304. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/graphql_types.py +0 -0
  305. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/metrics.py +0 -0
  306. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/models.py +0 -0
  307. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/public.py +0 -0
  308. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/s3.py +0 -0
  309. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/services.py +0 -0
  310. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/tokens.py +0 -0
  311. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/types.py +0 -0
  312. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/urls.py +0 -0
  313. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/uploads/views.py +0 -0
  314. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/__init__.py +0 -0
  315. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/_args_to_kwargs.py +0 -0
  316. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/_cache_key_encoder.py +0 -0
  317. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/_make_cache_key.py +0 -0
  318. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/_none_to_zero.py +0 -0
  319. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/format_string.py +0 -0
  320. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/json_encoder.py +0 -0
  321. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/path_mapping.py +0 -0
  322. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/public_api.py +0 -0
  323. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/testing.py +0 -0
  324. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/utils/type_checks.py +0 -0
  325. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/__init__.py +0 -0
  326. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/actions.py +0 -0
  327. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/backend_registry.py +0 -0
  328. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/backends/__init__.py +0 -0
  329. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/backends/celery.py +0 -0
  330. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/backends/local.py +0 -0
  331. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/backends/n8n.py +0 -0
  332. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/config.py +0 -0
  333. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/engine.py +0 -0
  334. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/event_registry.py +0 -0
  335. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/events.py +0 -0
  336. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/models.py +0 -0
  337. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/signal_bridge.py +0 -0
  338. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/tasks.py +0 -0
  339. {generalmanager-0.85.0 → generalmanager-0.86.0}/src/general_manager/workflow/telemetry.py +0 -0
  340. {generalmanager-0.85.0 → generalmanager-0.86.0}/tests/test_settings.py +0 -0
  341. {generalmanager-0.85.0 → generalmanager-0.86.0}/tests/test_urls.py +0 -0
  342. {generalmanager-0.85.0 → generalmanager-0.86.0}/tests/testing_asgi.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GeneralManager
3
- Version: 0.85.0
3
+ Version: 0.86.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.85.0"
7
+ version = "0.86.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.85.0
3
+ Version: 0.86.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
@@ -835,14 +835,25 @@ class GraphQL:
835
835
  graphene_type_name = f"{generalManagerClass.__name__}Type"
836
836
  fields: GraphQLFieldMap = {}
837
837
 
838
+ # Only declared typed-list inputs opt into native list output semantics.
839
+ input_fields = getattr(interface_cls, "input_fields", {})
838
840
  # Map Attribute Types to Graphene Fields
839
- for field_name, field_info in interface_cls.get_attribute_types().items():
841
+ for field_name, attribute_info in interface_cls.get_attribute_types().items():
842
+ field_info: Mapping[str, object] = attribute_info
843
+ input_field = input_fields.get(field_name)
844
+ is_collection_input = getattr(input_field, "is_collection", False) is True
845
+ if is_collection_input:
846
+ field_info = {**field_info, "is_collection_input": True}
840
847
  field_type = field_info["type"]
841
848
  resolved_manager_type = resolve_general_manager_type(
842
849
  field_type,
843
850
  cls.manager_registry,
844
851
  )
845
- resolved_field_type = resolved_manager_type or field_type
852
+ resolved_field_type = (
853
+ field_type
854
+ if is_collection_input
855
+ else resolved_manager_type or field_type
856
+ )
846
857
  fields[field_name] = cls._map_field_to_graphene_read(
847
858
  resolved_field_type,
848
859
  field_name,
@@ -873,10 +884,22 @@ class GraphQL:
873
884
  )
874
885
 
875
886
  fields[resolver_name] = resolve_stored_file
887
+ elif is_collection_input:
888
+ fields[resolver_name] = (
889
+ cls._create_measurement_resolver(field_name)
890
+ if safe_issubclass(get_args(field_type)[0], Measurement)
891
+ else _create_normal_resolver_fn(
892
+ field_name,
893
+ authorize_manager_collection=resolve_general_manager_type(
894
+ get_args(field_type)[0], cls.manager_registry
895
+ )
896
+ is not None,
897
+ )
898
+ )
876
899
  else:
877
900
  fields[resolver_name] = cls._create_resolver(
878
901
  field_name,
879
- resolved_field_type,
902
+ cast(type, resolved_field_type),
880
903
  )
881
904
  if (
882
905
  field_name.endswith("_list")
@@ -1396,6 +1419,24 @@ class GraphQL:
1396
1419
  Returns:
1397
1420
  object: Graphene field or type configured for the attribute.
1398
1421
  """
1422
+ if field_info and field_info.get("is_collection_input") is True:
1423
+ element = get_args(field_type)[0]
1424
+ manager_element = resolve_general_manager_type(
1425
+ element, GraphQL.manager_registry
1426
+ )
1427
+ if manager_element is not None:
1428
+ return graphene.List(
1429
+ graphene.NonNull(
1430
+ lambda: GraphQL.graphql_type_registry[manager_element.__name__]
1431
+ )
1432
+ )
1433
+ scalar = (
1434
+ MeasurementType
1435
+ if safe_issubclass(element, Measurement)
1436
+ else GraphQL._map_field_to_graphene_base_type(element)
1437
+ )
1438
+ return graphene.List(graphene.NonNull(scalar))
1439
+
1399
1440
  manager_type = resolve_general_manager_type(
1400
1441
  field_type,
1401
1442
  GraphQL.manager_registry,
@@ -92,8 +92,13 @@ def build_identification_arguments(
92
92
  # name is independent of the actual primary-key column name.
93
93
  is_orm_id = is_orm_identifier_input(manager_class, name)
94
94
  required = input_field.required or (for_mutation and is_orm_id)
95
+ is_collection = getattr(input_field, "is_collection", False) is True
96
+ element_type = (
97
+ input_field.collection_element_type if is_collection else input_field.type
98
+ )
99
+ assert element_type is not None
95
100
  manager_type = resolve_general_manager_type(
96
- input_field.type, get_graphql_manager_registry()
101
+ element_type, get_graphql_manager_registry()
97
102
  )
98
103
  if manager_type is not None:
99
104
  # Reuse custom mutation support for structured/composite manager
@@ -101,16 +106,30 @@ def build_identification_arguments(
101
106
  from general_manager.api.mutation import (
102
107
  _build_manager_argument_field,
103
108
  _uses_single_id_input,
109
+ _get_or_create_manager_input_type,
104
110
  )
105
111
 
112
+ if is_collection:
113
+ reference = (
114
+ graphene.ID
115
+ if _uses_single_id_input(manager_type)
116
+ else _get_or_create_manager_input_type(manager_type)
117
+ )
118
+ arguments[f"{name}_id"] = graphene.Argument(
119
+ graphene.List(graphene.NonNull(reference)), required=required
120
+ )
121
+ continue
106
122
  arguments[f"{name}_id"] = (
107
123
  graphene.Argument(graphene.ID, required=required)
108
124
  if _uses_single_id_input(manager_type)
109
125
  else _build_manager_argument_field(manager_type, required=required)
110
126
  )
111
127
  else:
112
- scalar = map_identification_scalar(manager_class, name, input_field.type)
113
- arguments[name] = graphene.Argument(scalar, required=required)
128
+ scalar = map_identification_scalar(manager_class, name, element_type)
129
+ arguments[name] = graphene.Argument(
130
+ graphene.List(graphene.NonNull(scalar)) if is_collection else scalar,
131
+ required=required,
132
+ )
114
133
  return arguments
115
134
 
116
135
 
@@ -1339,12 +1339,15 @@ def create_measurement_resolver(field_name: str) -> Resolver:
1339
1339
  return resolver
1340
1340
 
1341
1341
 
1342
- def create_normal_resolver(field_name: str) -> Resolver:
1342
+ def create_normal_resolver(
1343
+ field_name: str, *, authorize_manager_collection: bool = False
1344
+ ) -> Resolver:
1343
1345
  """
1344
1346
  Return a resolver for a scalar (non-list, non-Measurement) field.
1345
1347
 
1346
1348
  The generated resolver returns ``None`` when field read permission is denied;
1347
- otherwise it returns ``getattr(self, field_name)``.
1349
+ otherwise it returns ``getattr(self, field_name)``. Typed manager collections
1350
+ additionally omit members denied by the manager-level read gate.
1348
1351
  """
1349
1352
 
1350
1353
  def resolver(self: GeneralManager, info: GraphQLResolveInfo) -> object:
@@ -1356,11 +1359,18 @@ def create_normal_resolver(field_name: str) -> Resolver:
1356
1359
  if relation_id is not _NO_GROUPED_RELATION_ID_ALIAS:
1357
1360
  return relation_id
1358
1361
  _validate_grouped_field_projection(self, field_name)
1359
- return project_grouped_field_value(
1362
+ value = project_grouped_field_value(
1360
1363
  self,
1361
1364
  field_name,
1362
1365
  read_grouped_field_value(self, field_name),
1363
1366
  )
1367
+ if authorize_manager_collection and value is not None:
1368
+ return [
1369
+ member
1370
+ for member in cast(list[GeneralManager], value)
1371
+ if can_read_instance_for_user(member, info.context.user)
1372
+ ]
1373
+ return value
1364
1374
 
1365
1375
  return resolve_with_read_permission(
1366
1376
  self,
@@ -805,6 +805,10 @@ def create_filter_options(
805
805
 
806
806
  filter_fields: dict[str, GrapheneFieldType] = {}
807
807
  for attr_name, attr_info in field_type.Interface.get_attribute_types().items():
808
+ # Native constructor selections do not add a new GraphQL filter language.
809
+ input_field = getattr(field_type.Interface, "input_fields", {}).get(attr_name)
810
+ if getattr(input_field, "is_collection", False) is True:
811
+ continue
808
812
  effective_attr_info = _get_filter_relation_info(
809
813
  field_type,
810
814
  attr_name,
@@ -348,7 +348,14 @@ def resolve_subscription_dependencies(
348
348
  interface_cls = manager_class.Interface
349
349
 
350
350
  for input_name, input_field in interface_cls.input_fields.items():
351
- if not issubclass(input_field.type, GeneralManager):
351
+ manager_type = (
352
+ input_field.collection_element_type
353
+ if getattr(input_field, "is_collection", False) is True
354
+ else input_field.type
355
+ )
356
+ if not isinstance(manager_type, type) or not issubclass(
357
+ manager_type, GeneralManager
358
+ ):
352
359
  continue
353
360
 
354
361
  raw_value = instance._interface.identification.get(input_name)
@@ -359,7 +366,6 @@ def resolve_subscription_dependencies(
359
366
  for value in values:
360
367
  if isinstance(value, GeneralManager):
361
368
  identification = deepcopy(value.identification)
362
- manager_type = input_field.type
363
369
  if (
364
370
  manager_type is manager_class
365
371
  and identification == instance.identification
@@ -375,7 +381,6 @@ def resolve_subscription_dependencies(
375
381
  dep_list.append((manager_type, identification))
376
382
  elif isinstance(value, dict):
377
383
  identification_dict = deepcopy(cast(Identification, value))
378
- manager_type = input_field.type
379
384
  if (
380
385
  manager_type is manager_class
381
386
  and identification_dict == instance.identification
@@ -180,6 +180,11 @@ def _get_or_create_manager_input_type(
180
180
  for input_name, input_field in _manager_input_fields(manager_class).items():
181
181
  field_type = input_field.type
182
182
  required = input_field.required
183
+ if get_origin(field_type) is list:
184
+ fields[input_name] = graphene.InputField(
185
+ _mutation_input_type(field_type), required=required
186
+ )
187
+ continue
183
188
  if _is_general_manager_type(field_type):
184
189
  if _uses_single_id_input(field_type):
185
190
  fields[input_name] = graphene.ID(required=required)
@@ -368,7 +368,11 @@ def initialize_general_manager_classes(
368
368
  seen: set[str] = set()
369
369
  input_fields = getattr(general_manager_class.Interface, "input_fields", {})
370
370
  for attribute_name, attribute in input_fields.items():
371
- if isinstance(attribute, Input) and issubclass(attribute.type, _GM):
371
+ if (
372
+ isinstance(attribute, Input)
373
+ and isinstance(attribute.type, type)
374
+ and issubclass(attribute.type, _GM)
375
+ ):
372
376
  seen.add(attribute_name)
373
377
  yield attribute_name, attribute.type
374
378
 
@@ -36,10 +36,15 @@ from general_manager.bucket._ordering import (
36
36
  validate_ordering_fields,
37
37
  )
38
38
  from general_manager.bucket.projection import ProjectionRows
39
- from general_manager.manager.input import Input, InputDomain
39
+ from general_manager.manager.input import (
40
+ Input,
41
+ InputDomain,
42
+ _prepare_normalized_identification,
43
+ )
40
44
  from general_manager.utils.filter_parser import (
41
45
  FilterFunction,
42
46
  ParsedFilters,
47
+ ParsedFilterCriteria,
43
48
  create_filter_function,
44
49
  parse_filters,
45
50
  )
@@ -240,6 +245,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
240
245
  parse_filters(group, possible_values) for group in self._exclude_call_groups
241
246
  )
242
247
 
248
+ self._normalized_collections: dict[Hashable, object] = {}
243
249
  self._data: list[Combination] | None = None
244
250
  self._allowed_identifications: list[Combination] | None = None
245
251
  self._sort_fields: tuple[str, ...] = ()
@@ -687,7 +693,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
687
693
  self._ensure_as_of_compatible()
688
694
  combinations = self.generate_combinations()
689
695
  for combo in combinations:
690
- yield self._manager_class(**combo)
696
+ yield self._construct_manager(combo)
691
697
 
692
698
  def _project_rows(self, fields: tuple[str, ...]) -> ProjectionRows:
693
699
  """Project normalized calculation inputs without manager instances."""
@@ -712,7 +718,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
712
718
  tuple(
713
719
  resolve_calculation_input_value(
714
720
  interface_class,
715
- identification,
721
+ self._normalized_constructor_values(identification),
716
722
  field,
717
723
  resolved_values,
718
724
  )
@@ -803,8 +809,8 @@ class CalculationBucket(Bucket[GeneralManagerType]):
803
809
  or any(len(group) > 1 for group in self._exclude_call_groups)
804
810
  )
805
811
 
806
- @staticmethod
807
812
  def _matches_call_group(
813
+ self,
808
814
  manager: GeneralManagerType,
809
815
  group: ParsedFilters,
810
816
  ) -> bool:
@@ -814,9 +820,19 @@ class CalculationBucket(Bucket[GeneralManagerType]):
814
820
  value = getattr(manager, field_name)
815
821
  except AttributeError:
816
822
  return False
817
- for filter_func in definitions.get("filter_funcs", []):
818
- if not filter_func(value):
823
+ if "collection_criteria" in definitions:
824
+ dependencies = {
825
+ name: getattr(manager, name)
826
+ for name in self.input_fields[field_name].depends_on
827
+ }
828
+ if not self._collection_matches(
829
+ field_name, value, definitions, dependencies
830
+ ):
819
831
  return False
832
+ else:
833
+ for filter_func in definitions.get("filter_funcs", []):
834
+ if not filter_func(value):
835
+ return False
820
836
  for lookup, expected in definitions.get("filter_kwargs", {}).items():
821
837
  identification = getattr(value, "identification", None)
822
838
  lookup_parts = lookup.split("__") if lookup else []
@@ -904,13 +920,56 @@ class CalculationBucket(Bucket[GeneralManagerType]):
904
920
  identity_for=lambda combo: combo,
905
921
  )
906
922
 
923
+ def _normalize_collection(
924
+ self, name: str, value: object, context: Combination
925
+ ) -> object:
926
+ """Normalize a selection once for each dependency context in this plan."""
927
+ field = self.input_fields[name]
928
+ dependencies = {
929
+ dependency: context[dependency] for dependency in field.depends_on
930
+ }
931
+ key = (
932
+ name,
933
+ freeze_bucket_index_value(value),
934
+ freeze_bucket_index_value(dependencies),
935
+ )
936
+ if key not in self._normalized_collections:
937
+ self._normalized_collections[key] = field.cast(
938
+ value, dependencies, cache_context=(self._manager_class, name)
939
+ )
940
+ result = self._normalized_collections[key]
941
+ return list(result) if isinstance(result, list) else result
942
+
943
+ def _collection_matches(
944
+ self,
945
+ name: str,
946
+ value: object,
947
+ criteria: ParsedFilterCriteria,
948
+ context: Combination,
949
+ ) -> bool:
950
+ """Compare complete normalized selections with normalized alternatives."""
951
+ return all(
952
+ any(
953
+ value == self._normalize_collection(name, candidate, context)
954
+ for candidate in alternatives
955
+ )
956
+ for alternatives in criteria.get("collection_criteria", [])
957
+ )
958
+
959
+ def _normalized_constructor_values(self, combination: Combination) -> Combination:
960
+ """Mark normalized lists when reconstructing bucket managers or projections."""
961
+ return _prepare_normalized_identification(self._manager_class, combination)
962
+
963
+ def _construct_manager(self, combination: Combination) -> GeneralManagerType:
964
+ return self._manager_class(**self._normalized_constructor_values(combination))
965
+
907
966
  def _manager_combinations(
908
967
  self,
909
968
  combinations: list[Combination],
910
969
  ) -> list[GeneralManagerType]:
911
970
  """Instantiate managers for each raw input-combination dictionary."""
912
971
  self._ensure_as_of_compatible()
913
- return [self._manager_class(**combo) for combo in combinations]
972
+ return [self._construct_manager(combo) for combo in combinations]
914
973
 
915
974
  @staticmethod
916
975
  def _manager_identifications(
@@ -1165,16 +1224,56 @@ class CalculationBucket(Bucket[GeneralManagerType]):
1165
1224
  input_name: str = sorted_inputs[index]
1166
1225
  input_field = self.input_fields[input_name]
1167
1226
 
1168
- possible_values = self.get_possible_values(
1169
- input_name, input_field, current_combo
1170
- )
1227
+ field_filters = filters.get(input_name, {})
1228
+ field_excludes = excludes.get(input_name, {})
1229
+ possible_values: Iterable[object] | Bucket[GeneralManager] | None
1230
+ if input_field.is_collection and input_field.possible_values is None:
1231
+ if "candidate_values" in field_filters:
1232
+ possible_values = field_filters["candidate_values"]
1233
+ elif input_field.required:
1234
+ raise InvalidPossibleValuesError(input_name)
1235
+ else:
1236
+ possible_values = [None]
1237
+ else:
1238
+ possible_values = self.get_possible_values(
1239
+ input_name, input_field, current_combo
1240
+ )
1171
1241
  if possible_values is None:
1172
1242
  if input_passes_filters(input_name, current_combo):
1173
1243
  yield from helper(index + 1, current_combo)
1174
1244
  return
1175
1245
 
1176
- field_filters = filters.get(input_name, {})
1177
- field_excludes = excludes.get(input_name, {})
1246
+ if input_field.is_collection:
1247
+ from general_manager.interface.capabilities.calculation.input_resolution import (
1248
+ resolve_calculation_input_value,
1249
+ )
1250
+
1251
+ resolved_dependencies: Combination = {}
1252
+ for dependency in input_field.depends_on:
1253
+ resolve_calculation_input_value(
1254
+ cast(
1255
+ "type[CalculationInterface]", self._manager_class.Interface
1256
+ ),
1257
+ self._normalized_constructor_values(current_combo),
1258
+ dependency,
1259
+ resolved_dependencies,
1260
+ )
1261
+ for raw_value in possible_values:
1262
+ value = self._normalize_collection(
1263
+ input_name, raw_value, resolved_dependencies
1264
+ )
1265
+ if not self._collection_matches(
1266
+ input_name, value, field_filters, resolved_dependencies
1267
+ ):
1268
+ continue
1269
+ if field_excludes and self._collection_matches(
1270
+ input_name, value, field_excludes, resolved_dependencies
1271
+ ):
1272
+ continue
1273
+ current_combo[input_name] = value
1274
+ yield from helper(index + 1, current_combo)
1275
+ del current_combo[input_name]
1276
+ return
1178
1277
 
1179
1278
  # use filter_funcs and exclude_funcs to filter possible values
1180
1279
  if isinstance(possible_values, Bucket):
@@ -1197,7 +1296,9 @@ class CalculationBucket(Bucket[GeneralManagerType]):
1197
1296
  possible_values = list(possible_values)
1198
1297
 
1199
1298
  for value in possible_values:
1200
- if not isinstance(value, input_field.type):
1299
+ if not input_field.is_collection and not isinstance(
1300
+ value, input_field.type
1301
+ ):
1201
1302
  continue
1202
1303
  current_combo[input_name] = value
1203
1304
  yield from helper(index + 1, current_combo)
@@ -1247,7 +1348,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
1247
1348
  matching combinations have been found.
1248
1349
  """
1249
1350
  for combo in combinations:
1250
- manager = self._manager_class(**combo)
1351
+ manager = self._construct_manager(combo)
1251
1352
  if (
1252
1353
  allowed_identification_keys is not None
1253
1354
  and freeze_bucket_index_value(manager.identification)
@@ -1371,10 +1472,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
1371
1472
 
1372
1473
  return MaterializedBucket(
1373
1474
  self._manager_class,
1374
- tuple(self._manager_class(**combination) for combination in result),
1475
+ tuple(self._construct_manager(combination) for combination in result),
1375
1476
  snapshot=self._effective_search_date,
1376
1477
  )
1377
- return self._manager_class(**result)
1478
+ return self._construct_manager(result)
1378
1479
 
1379
1480
  def __contains__(self, item: GeneralManagerType) -> bool:
1380
1481
  """
@@ -368,12 +368,40 @@ class InterfaceBase(ABC):
368
368
  **kwargs: Named identification values matching the interface's input field names.
369
369
  """
370
370
  identification = self.parse_input_fields_to_identification(*args, **kwargs)
371
+ has_collections = any(
372
+ getattr(field, "is_collection", False) is True
373
+ for field in self.input_fields.values()
374
+ )
375
+ if not has_collections:
376
+ from general_manager.manager.general_manager import GeneralManager
377
+
378
+ has_collections = any(
379
+ isinstance(value, GeneralManager)
380
+ and getattr(
381
+ value.__dict__.get("_interface"), "_has_collection_inputs", False
382
+ )
383
+ is True
384
+ for value in identification.values()
385
+ )
386
+ if has_collections:
387
+ self._has_collection_inputs = True
388
+ # Preserve normalized objects before format_identification replaces managers.
389
+ self._resolved_input_values = {
390
+ name: list(value) if isinstance(value, list) else value
391
+ for name, value in identification.items()
392
+ }
371
393
  if len(identification) == 1:
372
394
  value = next(iter(identification.values()))
373
395
  if value.__class__ in _FORMATLESS_IDENTIFICATION_VALUE_TYPES:
374
396
  self.identification = identification
375
397
  return
376
398
  self.identification = self.format_identification(identification)
399
+ if has_collections:
400
+ from copy import deepcopy
401
+
402
+ for name, field in self.input_fields.items():
403
+ if getattr(field, "is_collection", False) is True:
404
+ self.identification[name] = deepcopy(self.identification[name])
377
405
 
378
406
  @classmethod
379
407
  def set_capability_selection(cls, selection: "CapabilitySelection") -> None:
@@ -1086,7 +1114,9 @@ class InterfaceBase(ABC):
1086
1114
  if input_field.required:
1087
1115
  raise InvalidInputTypeError(name, type(value), input_field.type)
1088
1116
  return
1089
- if not isinstance(value, input_field.type):
1117
+ if getattr(input_field, "is_collection", False) is True:
1118
+ input_field.validate_collection_type(value, name)
1119
+ elif not isinstance(value, input_field.type):
1090
1120
  raise InvalidInputTypeError(name, type(value), input_field.type)
1091
1121
  if (
1092
1122
  input_field.min_value is not None or input_field.max_value is not None
@@ -13,7 +13,10 @@ if TYPE_CHECKING: # pragma: no cover
13
13
 
14
14
  def track_manager_input(value: object) -> None:
15
15
  """Replay the identification dependency for a cached manager input."""
16
- if isinstance(value, GeneralManager):
16
+ if isinstance(value, list):
17
+ for member in value:
18
+ track_manager_input(member)
19
+ elif isinstance(value, GeneralManager):
17
20
  value.__class__._track_identification_dependency(value.identification)
18
21
 
19
22
 
@@ -33,7 +36,12 @@ def resolve_calculation_input_value(
33
36
  if field_name in resolved_values:
34
37
  value = resolved_values[field_name]
35
38
  track_manager_input(value)
36
- return value
39
+ return (
40
+ list(value)
41
+ if isinstance(value, list)
42
+ and interface_cls.input_fields[field_name].is_collection
43
+ else value
44
+ )
37
45
 
38
46
  field = interface_cls.input_fields[field_name]
39
47
  dependencies = {
@@ -52,4 +60,4 @@ def resolve_calculation_input_value(
52
60
  )
53
61
  track_manager_input(value)
54
62
  resolved_values[field_name] = value
55
- return value
63
+ return list(value) if isinstance(value, list) and field.is_collection else value
@@ -388,9 +388,14 @@ class GeneralManager(metaclass=GeneralManagerMeta):
388
388
  def __reduce__(self) -> tuple[object, tuple[object, ...]]:
389
389
  """Provide snapshot-preserving pickling support for this manager."""
390
390
  effective = _legacy_effective_search_date(self)
391
+ from general_manager.manager.input import _prepare_normalized_identification
392
+
393
+ values = tuple(
394
+ _prepare_normalized_identification(self.__class__, self.__id).values()
395
+ )
391
396
  return (
392
397
  _reconstruct_general_manager,
393
- (self.__class__, tuple(self.__id.values()), effective),
398
+ (self.__class__, values, effective),
394
399
  )
395
400
 
396
401
  def __or__(
@@ -433,6 +438,13 @@ class GeneralManager(metaclass=GeneralManagerMeta):
433
438
  @property
434
439
  def identification(self) -> dict[str, object]:
435
440
  """Return the identification dictionary used to fetch the managed object."""
441
+ if (
442
+ getattr(self.__dict__.get("_interface"), "_has_collection_inputs", False)
443
+ is True
444
+ ):
445
+ from copy import deepcopy
446
+
447
+ return deepcopy(self.__id)
436
448
  return self.__id
437
449
 
438
450
  @property
@@ -795,8 +807,9 @@ class GeneralManager(metaclass=GeneralManagerMeta):
795
807
  )
796
808
  return cast(Bucket[Self], cls.Interface.filter())
797
809
 
798
- @staticmethod
810
+ @classmethod
799
811
  def __parse_identification(
812
+ cls,
800
813
  kwargs: dict[str, object],
801
814
  ) -> dict[str, object] | None:
802
815
  """
@@ -823,7 +836,17 @@ class GeneralManager(metaclass=GeneralManagerMeta):
823
836
 
824
837
  output: dict[str, object] = {}
825
838
  changed = False
839
+ fields = getattr(getattr(cls, "Interface", None), "input_fields", {})
826
840
  for key, value in kwargs.items():
841
+ input_name = key.split("__", 1)[0]
842
+ input_field = fields.get(input_name)
843
+ if input_field is None and input_name.endswith("_id"):
844
+ input_field = fields.get(input_name[:-3])
845
+ if getattr(input_field, "is_collection", False) is True:
846
+ # Collection casting retains resolved manager members; flattening
847
+ # them here would rerun nested collection normalizers.
848
+ output[key] = value
849
+ continue
827
850
  if isinstance(value, GeneralManager):
828
851
  output[key] = GeneralManager.__lookup_identifier(value)
829
852
  changed = True