GeneralManager 0.89.2__tar.gz → 0.89.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.
- {generalmanager-0.89.2/src/GeneralManager.egg-info → generalmanager-0.89.3}/PKG-INFO +1 -1
- {generalmanager-0.89.2 → generalmanager-0.89.3}/pyproject.toml +1 -1
- {generalmanager-0.89.2 → generalmanager-0.89.3/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/GeneralManager.egg-info/SOURCES.txt +2 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_query_permissions.py +53 -6
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_resolvers.py +16 -1
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/base_interface.py +12 -3
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/mutations.py +242 -14
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +54 -7
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/request/__init__.py +20 -5
- generalmanager-0.89.3/src/general_manager/interface/capabilities/request/relation_inputs.py +249 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/manager/general_manager.py +21 -5
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/manager_based_permission.py +142 -18
- generalmanager-0.89.3/src/general_manager/permission/permission_data_manager.py +443 -0
- generalmanager-0.89.3/src/general_manager/permission/relation_aliases.py +58 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/authorization.py +4 -1
- generalmanager-0.89.2/src/general_manager/permission/permission_data_manager.py +0 -132
- {generalmanager-0.89.2 → generalmanager-0.89.3}/LICENSE +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/README.md +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/setup.cfg +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_filter_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_groups.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_identifiers.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_ordering.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_output.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_type.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_units.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_value_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/mutation_controls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/apps.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/_materialized_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/_ordering.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/database_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/excel_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/projection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/_dependency_graph.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/batch_refresh.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/cache/transaction_barrier.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/audit_identity.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/execution.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/judges/result_set.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/outcomes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/graphql_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/mutation_inputs.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/action_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/binding_diagnostics.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/budget.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/calculation_scope.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/calculations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/catalog.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/category_binding.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/choice_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/clarification.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/conversion.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/cross_query.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/deferred_calculations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/deferred_schema.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/events.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/evidence.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/evidence_selection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/group_actions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/planner.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/planner_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/provider_calls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/resolver.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/scheduler.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/schema_projection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/selector_clarification.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/selector_question.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/synthesis.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/planned/validation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/schema_inspection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/turns.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/conf.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/bundles/excel.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/create_many.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/history_query.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm_utils/collection_probes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/excel.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/excel_store.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/excel_workbook.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/excel.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/unit_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/logging.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/sync_read_only.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/manager/bulk_create.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/py.typed +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/identity.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/projection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/_args_to_kwargs.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/_cache_key_encoder.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/_make_cache_key.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/_none_to_zero.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/executable_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/tests/test_settings.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/tests/test_urls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.89.3}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.89.
|
|
3
|
+
Version: 0.89.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.89.
|
|
7
|
+
version = "0.89.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.89.
|
|
3
|
+
Version: 0.89.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
|
|
@@ -232,6 +232,7 @@ src/general_manager/interface/capabilities/read_only/_types.py
|
|
|
232
232
|
src/general_manager/interface/capabilities/read_only/lifecycle.py
|
|
233
233
|
src/general_manager/interface/capabilities/read_only/management.py
|
|
234
234
|
src/general_manager/interface/capabilities/request/__init__.py
|
|
235
|
+
src/general_manager/interface/capabilities/request/relation_inputs.py
|
|
235
236
|
src/general_manager/interface/infrastructure/__init__.py
|
|
236
237
|
src/general_manager/interface/infrastructure/startup_hooks.py
|
|
237
238
|
src/general_manager/interface/infrastructure/system_checks.py
|
|
@@ -296,6 +297,7 @@ src/general_manager/permission/manager_based_permission.py
|
|
|
296
297
|
src/general_manager/permission/mutation_permission.py
|
|
297
298
|
src/general_manager/permission/permission_checks.py
|
|
298
299
|
src/general_manager/permission/permission_data_manager.py
|
|
300
|
+
src/general_manager/permission/relation_aliases.py
|
|
299
301
|
src/general_manager/permission/utils.py
|
|
300
302
|
src/general_manager/rule/__init__.py
|
|
301
303
|
src/general_manager/rule/handler.py
|
{generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_query_permissions.py
RENAMED
|
@@ -219,7 +219,7 @@ class _NativeQueryStructure:
|
|
|
219
219
|
for name in names:
|
|
220
220
|
if name not in self.additional:
|
|
221
221
|
self.additional[name] = additional_local_read_permission(
|
|
222
|
-
self.permission, name
|
|
222
|
+
self.permission, name, manager=self.manager
|
|
223
223
|
)
|
|
224
224
|
if self.additional[name] is None:
|
|
225
225
|
return None
|
|
@@ -459,7 +459,8 @@ def authorize_query_fields(
|
|
|
459
459
|
if getattr_static(permission, "__based_on__", None) is not None:
|
|
460
460
|
return True
|
|
461
461
|
return any(
|
|
462
|
-
additional_local_read_permission(permission, name)
|
|
462
|
+
additional_local_read_permission(permission, name, manager=type(instance))
|
|
463
|
+
is not False
|
|
463
464
|
for name in names
|
|
464
465
|
)
|
|
465
466
|
|
|
@@ -490,8 +491,37 @@ def authorize_query_fields(
|
|
|
490
491
|
aliases, names, native_relations = _operand_field_names(
|
|
491
492
|
type(instance), field, attributes, native_paths=native_paths
|
|
492
493
|
)
|
|
493
|
-
|
|
494
|
-
|
|
494
|
+
# A standard delegated policy already resolves its concrete target
|
|
495
|
+
# during the normal field check. Inspect that same permission object,
|
|
496
|
+
# not a second relation read or a static declared target type.
|
|
497
|
+
from general_manager.permission.manager_based_permission import (
|
|
498
|
+
_can_prepare_local_read_definitions,
|
|
499
|
+
additional_resolved_read_permission,
|
|
500
|
+
)
|
|
501
|
+
from general_manager.permission.base_permission import BasePermission
|
|
502
|
+
|
|
503
|
+
permission = getattr_static(instance, "Permission", None)
|
|
504
|
+
resolved_budget = (
|
|
505
|
+
budget_additional_permissions_only
|
|
506
|
+
and getattr_static(permission, "__based_on__", None) is not None
|
|
507
|
+
and _can_prepare_local_read_definitions(permission)
|
|
508
|
+
)
|
|
509
|
+
charged = False
|
|
510
|
+
|
|
511
|
+
def charge_resolved(resolved: BasePermission, name: str) -> None:
|
|
512
|
+
"""Charge this operand once when its resolved policy adds or may add restrictions."""
|
|
513
|
+
nonlocal charged
|
|
514
|
+
if (
|
|
515
|
+
not charged
|
|
516
|
+
and additional_resolved_read_permission(resolved, name) is not False
|
|
517
|
+
):
|
|
518
|
+
budget.charge()
|
|
519
|
+
charged = True
|
|
520
|
+
|
|
521
|
+
if (
|
|
522
|
+
budget_additional_permissions_only
|
|
523
|
+
and not resolved_budget
|
|
524
|
+
and needs_additional_budget(instance, names)
|
|
495
525
|
):
|
|
496
526
|
budget.charge()
|
|
497
527
|
known_fields = set(attributes) | set(instance.identification)
|
|
@@ -500,8 +530,25 @@ def authorize_query_fields(
|
|
|
500
530
|
known_fields.update(instance.Interface.input_fields)
|
|
501
531
|
if not names.intersection(known_fields):
|
|
502
532
|
raise QueryFieldPermissionError(field)
|
|
503
|
-
|
|
504
|
-
|
|
533
|
+
for name in names:
|
|
534
|
+
if resolved_budget:
|
|
535
|
+
|
|
536
|
+
def before_check(
|
|
537
|
+
resolved: BasePermission, field_name: str = name
|
|
538
|
+
) -> None:
|
|
539
|
+
"""Account for the exact resolved permission before its normal field check."""
|
|
540
|
+
charge_resolved(resolved, field_name)
|
|
541
|
+
|
|
542
|
+
allowed = check_read_permission(
|
|
543
|
+
instance,
|
|
544
|
+
info,
|
|
545
|
+
name,
|
|
546
|
+
before_check=before_check,
|
|
547
|
+
)
|
|
548
|
+
else:
|
|
549
|
+
allowed = check_read_permission(instance, info, name)
|
|
550
|
+
if not allowed:
|
|
551
|
+
raise QueryFieldPermissionError(field)
|
|
505
552
|
for relation in sorted(native_relations):
|
|
506
553
|
# An ORM attname is a scalar spelling of a related field. Give it
|
|
507
554
|
# the same target row/leaf gates as an explicit relation path.
|
{generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/api/graphql_resolvers.py
RENAMED
|
@@ -1140,6 +1140,8 @@ def check_read_permission_for_user(
|
|
|
1140
1140
|
instance: GeneralManager,
|
|
1141
1141
|
user: object,
|
|
1142
1142
|
field_name: str,
|
|
1143
|
+
*,
|
|
1144
|
+
before_check: Callable[[BasePermission], None] | None = None,
|
|
1143
1145
|
) -> bool:
|
|
1144
1146
|
"""
|
|
1145
1147
|
Return ``True`` if *user* may read *field_name* on *instance*.
|
|
@@ -1147,10 +1149,15 @@ def check_read_permission_for_user(
|
|
|
1147
1149
|
When the manager defines a Permission class, this calls
|
|
1148
1150
|
``Permission(instance, user).check_permission("read", field_name)``.
|
|
1149
1151
|
Managers without a Permission class default to allowing the field read.
|
|
1152
|
+
The internal ``before_check`` hook may account for the resolved policy,
|
|
1153
|
+
without constructing it twice or replacing its authorization decision.
|
|
1150
1154
|
"""
|
|
1151
1155
|
PermissionClass: type[BasePermission] | None = getattr(instance, "Permission", None)
|
|
1152
1156
|
if PermissionClass:
|
|
1153
|
-
|
|
1157
|
+
permission = PermissionClass(instance, user)
|
|
1158
|
+
if before_check is not None:
|
|
1159
|
+
before_check(permission)
|
|
1160
|
+
return permission.check_permission("read", field_name)
|
|
1154
1161
|
return True
|
|
1155
1162
|
|
|
1156
1163
|
|
|
@@ -1158,6 +1165,8 @@ def check_read_permission(
|
|
|
1158
1165
|
instance: GeneralManager,
|
|
1159
1166
|
info: GraphQLResolveInfo,
|
|
1160
1167
|
field_name: str,
|
|
1168
|
+
*,
|
|
1169
|
+
before_check: Callable[[BasePermission], None] | None = None,
|
|
1161
1170
|
) -> bool:
|
|
1162
1171
|
"""
|
|
1163
1172
|
Return ``True`` if the request user may read *field_name* on *instance*.
|
|
@@ -1165,7 +1174,13 @@ def check_read_permission(
|
|
|
1165
1174
|
When the manager defines a Permission class, this calls
|
|
1166
1175
|
``Permission(instance, user).check_permission("read", field_name)``.
|
|
1167
1176
|
Managers without a Permission class default to allowing the field read.
|
|
1177
|
+
The internal ``before_check`` hook may account for the resolved policy,
|
|
1178
|
+
without constructing it twice or replacing its authorization decision.
|
|
1168
1179
|
"""
|
|
1180
|
+
if before_check is not None:
|
|
1181
|
+
return check_read_permission_for_user(
|
|
1182
|
+
instance, info.context.user, field_name, before_check=before_check
|
|
1183
|
+
)
|
|
1169
1184
|
return check_read_permission_for_user(instance, info.context.user, field_name)
|
|
1170
1185
|
|
|
1171
1186
|
|
{generalmanager-0.89.2 → generalmanager-0.89.3}/src/general_manager/interface/base_interface.py
RENAMED
|
@@ -1183,7 +1183,6 @@ class InterfaceBase(ABC):
|
|
|
1183
1183
|
The capability-level create result mapping.
|
|
1184
1184
|
"""
|
|
1185
1185
|
reject_historical_mutation()
|
|
1186
|
-
observer = cls.get_capability_handler("observability")
|
|
1187
1186
|
|
|
1188
1187
|
def _invoke() -> dict[str, object]:
|
|
1189
1188
|
"""
|
|
@@ -1201,12 +1200,22 @@ class InterfaceBase(ABC):
|
|
|
1201
1200
|
return create_handler(cls, *args, **kwargs)
|
|
1202
1201
|
raise NotImplementedError(f"{cls.__name__} does not support create.")
|
|
1203
1202
|
|
|
1203
|
+
return cls._observe_create(args, kwargs, _invoke)
|
|
1204
|
+
|
|
1205
|
+
@classmethod
|
|
1206
|
+
def _observe_create(
|
|
1207
|
+
cls,
|
|
1208
|
+
args: tuple[object, ...],
|
|
1209
|
+
kwargs: dict[str, object],
|
|
1210
|
+
invoke: Callable[[], dict[str, object]],
|
|
1211
|
+
) -> dict[str, object]:
|
|
1212
|
+
"""Share the public create observation envelope with ORM manager writes."""
|
|
1204
1213
|
return cls._execute_with_observability(
|
|
1205
1214
|
target=cls,
|
|
1206
1215
|
operation="create",
|
|
1207
1216
|
payload={"args": args, "kwargs": kwargs},
|
|
1208
|
-
func=
|
|
1209
|
-
observer=
|
|
1217
|
+
func=invoke,
|
|
1218
|
+
observer=cls.get_capability_handler("observability"),
|
|
1210
1219
|
)
|
|
1211
1220
|
|
|
1212
1221
|
@classmethod
|
|
@@ -5,11 +5,14 @@ from __future__ import annotations
|
|
|
5
5
|
from collections.abc import Iterator
|
|
6
6
|
from contextlib import AbstractContextManager, contextmanager
|
|
7
7
|
from contextvars import ContextVar
|
|
8
|
-
from
|
|
8
|
+
from copy import copy, deepcopy
|
|
9
|
+
from dataclasses import dataclass, field
|
|
10
|
+
from typing import TYPE_CHECKING, Any, ClassVar, Protocol, cast
|
|
9
11
|
|
|
10
12
|
from django.contrib.auth import get_user_model
|
|
11
13
|
from django.db import DEFAULT_DB_ALIAS, models, router, transaction
|
|
12
14
|
from django.db.models import NOT_PROVIDED
|
|
15
|
+
from django.db.models.fields.related_descriptors import ForwardManyToOneDescriptor
|
|
13
16
|
|
|
14
17
|
from general_manager.cache.data_change_context import (
|
|
15
18
|
mark_data_change_unchanged,
|
|
@@ -53,7 +56,9 @@ from .support import (
|
|
|
53
56
|
)
|
|
54
57
|
|
|
55
58
|
if TYPE_CHECKING: # pragma: no cover
|
|
59
|
+
from django.db.models.fields.reverse_related import ForeignObjectRel
|
|
56
60
|
from general_manager.interface.orm_interface import OrmInterfaceBase
|
|
61
|
+
from general_manager.manager.general_manager import GeneralManager
|
|
57
62
|
|
|
58
63
|
type OrmInterfaceClass = type["OrmInterfaceBase[models.Model]"]
|
|
59
64
|
type OrmInterfaceInstance = "OrmInterfaceBase[models.Model]"
|
|
@@ -61,6 +66,110 @@ type MutationPayload = dict[str, object]
|
|
|
61
66
|
type ManyToManyPayload = dict[str, list[object]]
|
|
62
67
|
type MutationResult = dict[str, object]
|
|
63
68
|
|
|
69
|
+
|
|
70
|
+
class _CreatePermissionTargetChangedError(PermissionError):
|
|
71
|
+
"""The prepared create no longer targets the database or key authorized."""
|
|
72
|
+
|
|
73
|
+
def __init__(self) -> None:
|
|
74
|
+
super().__init__("The authorized ORM create relation target changed.")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class _UnboundRoutedCreatePermissionError(PermissionError):
|
|
78
|
+
"""A custom writer cannot bind its dynamic route to the permission check."""
|
|
79
|
+
|
|
80
|
+
def __init__(self) -> None:
|
|
81
|
+
super().__init__(
|
|
82
|
+
"Resolving a related object during a custom ORM create "
|
|
83
|
+
"requires a fixed database alias."
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass(slots=True)
|
|
88
|
+
class _RoutedCreatePermission:
|
|
89
|
+
"""Share one prepared model between its permission check and write."""
|
|
90
|
+
|
|
91
|
+
manager: type[GeneralManager]
|
|
92
|
+
payload: MutationPayload
|
|
93
|
+
interface: OrmInterfaceClass
|
|
94
|
+
shares_source: bool
|
|
95
|
+
source: models.Model | None = None
|
|
96
|
+
routing_hint: models.Model | None = None
|
|
97
|
+
checked_relations: dict[str, tuple[models.ForeignKey[models.Model], object]] = (
|
|
98
|
+
field(default_factory=dict)
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
def get_source(self) -> models.Model:
|
|
102
|
+
"""Initialize Django defaults only when a permission needs the source."""
|
|
103
|
+
if not self.shares_source:
|
|
104
|
+
raise _UnboundRoutedCreatePermissionError
|
|
105
|
+
if self.source is None:
|
|
106
|
+
self.source = self.interface._model()
|
|
107
|
+
return self.source
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def database_alias(self) -> str | None:
|
|
111
|
+
"""Return the chosen database once the check resolves a related row."""
|
|
112
|
+
return self.routing_hint._state.db if self.routing_hint is not None else None
|
|
113
|
+
|
|
114
|
+
def verify_target(
|
|
115
|
+
self, instance: models.Model, configured_database: str | None
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Reject routing or relation-key changes introduced by model validation."""
|
|
118
|
+
if self.database_alias is not None and self.database_alias != (
|
|
119
|
+
configured_database
|
|
120
|
+
or router.db_for_write(type(instance), instance=instance)
|
|
121
|
+
):
|
|
122
|
+
raise _CreatePermissionTargetChangedError
|
|
123
|
+
if any(
|
|
124
|
+
relation.target_field.to_python(getattr(instance, attname)) != value
|
|
125
|
+
for attname, (relation, value) in self.checked_relations.items()
|
|
126
|
+
):
|
|
127
|
+
raise _CreatePermissionTargetChangedError
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
_routed_create_check = ContextVar[_RoutedCreatePermission | None](
|
|
131
|
+
"routed_create_check", default=None
|
|
132
|
+
)
|
|
133
|
+
_routed_create_write = ContextVar[tuple[models.Model, _RoutedCreatePermission] | None](
|
|
134
|
+
"routed_create_write", default=None
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _copy_create_source(
|
|
139
|
+
source: models.Model, *, isolate_defaults: bool = False
|
|
140
|
+
) -> models.Model:
|
|
141
|
+
"""Copy ORM state, with isolated field defaults for retryable writes."""
|
|
142
|
+
instance = object.__new__(type(source))
|
|
143
|
+
instance.__dict__.update(source.__dict__)
|
|
144
|
+
if isolate_defaults:
|
|
145
|
+
for concrete in source._meta.concrete_fields:
|
|
146
|
+
if concrete.attname in source.__dict__:
|
|
147
|
+
instance.__dict__[concrete.attname] = deepcopy(
|
|
148
|
+
source.__dict__[concrete.attname]
|
|
149
|
+
)
|
|
150
|
+
instance._state = copy(source._state)
|
|
151
|
+
vars(instance._state)["fields_cache"] = dict(
|
|
152
|
+
cast(dict[str, object], source._state.fields_cache)
|
|
153
|
+
)
|
|
154
|
+
return instance
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
@contextmanager
|
|
158
|
+
def _bind_routed_create_write(
|
|
159
|
+
instance: models.Model,
|
|
160
|
+
permission: _RoutedCreatePermission | None,
|
|
161
|
+
) -> Iterator[None]:
|
|
162
|
+
"""Give the existing save hook the authorization for this exact model."""
|
|
163
|
+
if permission is None:
|
|
164
|
+
yield
|
|
165
|
+
return
|
|
166
|
+
token = _routed_create_write.set((instance, permission))
|
|
167
|
+
try:
|
|
168
|
+
yield
|
|
169
|
+
finally:
|
|
170
|
+
_routed_create_write.reset(token)
|
|
171
|
+
|
|
172
|
+
|
|
64
173
|
_save_with_history_savepoint = ContextVar(
|
|
65
174
|
"save_with_history_savepoint",
|
|
66
175
|
default=True,
|
|
@@ -94,6 +203,37 @@ def _mutation_atomic(
|
|
|
94
203
|
return transaction.atomic(savepoint=False)
|
|
95
204
|
|
|
96
205
|
|
|
206
|
+
class _ModelPkState(Protocol):
|
|
207
|
+
"""Django's PK completeness check, absent from older stubs."""
|
|
208
|
+
|
|
209
|
+
def _is_pk_set(self) -> bool: ...
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def _discard_alternate_key_cache(
|
|
213
|
+
instance: models.Model, name: str, related: models.Model
|
|
214
|
+
) -> None:
|
|
215
|
+
"""Keep Django assignment checks and reload the current alternate-key owner."""
|
|
216
|
+
descriptor = getattr(type(instance), name, None)
|
|
217
|
+
if not isinstance(descriptor, ForwardManyToOneDescriptor):
|
|
218
|
+
return
|
|
219
|
+
relation = descriptor.field
|
|
220
|
+
if (
|
|
221
|
+
not isinstance(relation, models.ForeignKey)
|
|
222
|
+
or relation.target_field.primary_key
|
|
223
|
+
or not cast(_ModelPkState, related)._is_pk_set()
|
|
224
|
+
or not relation.is_cached(instance)
|
|
225
|
+
):
|
|
226
|
+
# Leave unsaved objects cached so Django still rejects them at save.
|
|
227
|
+
return
|
|
228
|
+
relation.delete_cached_value(instance)
|
|
229
|
+
reverse = cast("ForeignObjectRel", relation.remote_field)
|
|
230
|
+
if (
|
|
231
|
+
not reverse.multiple
|
|
232
|
+
and reverse.get_cached_value(related, default=None) is instance
|
|
233
|
+
):
|
|
234
|
+
reverse.delete_cached_value(related)
|
|
235
|
+
|
|
236
|
+
|
|
97
237
|
class OrmMutationCapability(BaseCapability):
|
|
98
238
|
"""Common utilities to modify ORM instances."""
|
|
99
239
|
|
|
@@ -144,6 +284,8 @@ class OrmMutationCapability(BaseCapability):
|
|
|
144
284
|
raise InvalidFieldValueError(key, value) from error
|
|
145
285
|
except TypeError as error:
|
|
146
286
|
raise InvalidFieldTypeError(key, error) from error
|
|
287
|
+
if isinstance(value, models.Model):
|
|
288
|
+
_discard_alternate_key_cache(instance, key, value)
|
|
147
289
|
return instance
|
|
148
290
|
|
|
149
291
|
return call_with_observability(
|
|
@@ -202,6 +344,15 @@ class OrmMutationCapability(BaseCapability):
|
|
|
202
344
|
"""
|
|
203
345
|
support = get_support_capability(interface_cls)
|
|
204
346
|
database_alias = support.get_database_alias(interface_cls)
|
|
347
|
+
create_write = _routed_create_write.get()
|
|
348
|
+
create_permission = (
|
|
349
|
+
create_write[1]
|
|
350
|
+
if create_write is not None and create_write[0] is instance
|
|
351
|
+
else None
|
|
352
|
+
)
|
|
353
|
+
write_database = (
|
|
354
|
+
create_permission.database_alias if create_permission else None
|
|
355
|
+
) or database_alias
|
|
205
356
|
from general_manager.manager.bulk_create import (
|
|
206
357
|
CreateManyUnsupportedError,
|
|
207
358
|
enclosing_create_many_batch,
|
|
@@ -216,7 +367,7 @@ class OrmMutationCapability(BaseCapability):
|
|
|
216
367
|
if database_alias:
|
|
217
368
|
instance._state.db = database_alias
|
|
218
369
|
atomic_context = _mutation_atomic(
|
|
219
|
-
|
|
370
|
+
write_database,
|
|
220
371
|
savepoint=_save_with_history_savepoint.get(),
|
|
221
372
|
)
|
|
222
373
|
with atomic_context:
|
|
@@ -237,8 +388,10 @@ class OrmMutationCapability(BaseCapability):
|
|
|
237
388
|
!= batch.database_alias
|
|
238
389
|
):
|
|
239
390
|
raise CreateManyUnsupportedError.routing()
|
|
240
|
-
if
|
|
241
|
-
|
|
391
|
+
if create_permission is not None:
|
|
392
|
+
create_permission.verify_target(instance, database_alias)
|
|
393
|
+
if write_database:
|
|
394
|
+
instance.save(using=write_database)
|
|
242
395
|
else:
|
|
243
396
|
instance.save()
|
|
244
397
|
return instance.pk
|
|
@@ -371,6 +524,16 @@ class OrmCreateCapability(BaseCapability):
|
|
|
371
524
|
wrapped.
|
|
372
525
|
"""
|
|
373
526
|
_ = args
|
|
527
|
+
return self._create(interface_cls, kwargs)
|
|
528
|
+
|
|
529
|
+
def _create(
|
|
530
|
+
self,
|
|
531
|
+
interface_cls: OrmInterfaceClass,
|
|
532
|
+
kwargs: MutationPayload,
|
|
533
|
+
*,
|
|
534
|
+
permission: _RoutedCreatePermission | None = None,
|
|
535
|
+
) -> MutationResult:
|
|
536
|
+
"""Persist a create using the initialized source shared with its check."""
|
|
374
537
|
payload_snapshot = {"kwargs": dict(kwargs)}
|
|
375
538
|
|
|
376
539
|
def _perform() -> MutationResult:
|
|
@@ -399,6 +562,10 @@ class OrmCreateCapability(BaseCapability):
|
|
|
399
562
|
if enclosing_create_many_batch() is not None:
|
|
400
563
|
validate_create_many_record(normalized_simple)
|
|
401
564
|
mutation = _mutation_capability_for(interface_cls)
|
|
565
|
+
source = permission.source if permission is not None else None
|
|
566
|
+
authorized_database = (
|
|
567
|
+
permission.database_alias if permission is not None else None
|
|
568
|
+
)
|
|
402
569
|
if has_upload_candidates(normalized_simple):
|
|
403
570
|
prepared = prepare_upload_claims(
|
|
404
571
|
interface_cls,
|
|
@@ -407,10 +574,18 @@ class OrmCreateCapability(BaseCapability):
|
|
|
407
574
|
actor_id=creator_id,
|
|
408
575
|
target_pk=None,
|
|
409
576
|
)
|
|
577
|
+
if authorized_database not in (None, prepared.database_alias):
|
|
578
|
+
raise _CreatePermissionTargetChangedError
|
|
410
579
|
|
|
411
580
|
def _create_claimed() -> MutationResult:
|
|
412
581
|
locked = lock_upload_claims(prepared)
|
|
413
|
-
|
|
582
|
+
# An upload may retry the transaction. Each attempt starts
|
|
583
|
+
# with the same authorized defaults and a fresh model state.
|
|
584
|
+
instance = (
|
|
585
|
+
_copy_create_source(source, isolate_defaults=True)
|
|
586
|
+
if source is not None
|
|
587
|
+
else interface_cls._model()
|
|
588
|
+
)
|
|
414
589
|
ordinary_values = {
|
|
415
590
|
key: value
|
|
416
591
|
for key, value in normalized_simple.items()
|
|
@@ -431,12 +606,13 @@ class OrmCreateCapability(BaseCapability):
|
|
|
431
606
|
instance,
|
|
432
607
|
reserved_values,
|
|
433
608
|
)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
609
|
+
with _bind_routed_create_write(claimed_instance, permission):
|
|
610
|
+
claimed_pk = mutation.save_with_history(
|
|
611
|
+
interface_cls,
|
|
612
|
+
claimed_instance,
|
|
613
|
+
creator_id=creator_id,
|
|
614
|
+
history_comment=history_comment,
|
|
615
|
+
)
|
|
440
616
|
mutation.apply_many_to_many(
|
|
441
617
|
interface_cls,
|
|
442
618
|
claimed_instance,
|
|
@@ -448,12 +624,16 @@ class OrmCreateCapability(BaseCapability):
|
|
|
448
624
|
|
|
449
625
|
return run_upload_transaction(prepared, _create_claimed)
|
|
450
626
|
instance = mutation.assign_simple_attributes(
|
|
451
|
-
interface_cls,
|
|
627
|
+
interface_cls,
|
|
628
|
+
source if source is not None else interface_cls._model(),
|
|
629
|
+
normalized_simple,
|
|
452
630
|
)
|
|
453
631
|
support = get_support_capability(interface_cls)
|
|
454
632
|
database_alias = support.get_database_alias(interface_cls)
|
|
455
|
-
|
|
456
|
-
|
|
633
|
+
with (
|
|
634
|
+
_mutation_atomic(authorized_database or database_alias),
|
|
635
|
+
_bind_routed_create_write(instance, permission),
|
|
636
|
+
):
|
|
457
637
|
with _without_save_with_history_savepoint():
|
|
458
638
|
pk = mutation.save_with_history(
|
|
459
639
|
interface_cls,
|
|
@@ -477,6 +657,54 @@ class OrmCreateCapability(BaseCapability):
|
|
|
477
657
|
)
|
|
478
658
|
|
|
479
659
|
|
|
660
|
+
def _create_for_manager(
|
|
661
|
+
interface: OrmInterfaceClass,
|
|
662
|
+
manager: type[GeneralManager],
|
|
663
|
+
payload: MutationPayload,
|
|
664
|
+
creator_id: int | None,
|
|
665
|
+
history_comment: str | None,
|
|
666
|
+
) -> MutationResult:
|
|
667
|
+
"""Use the prepared model for permission checks in canonical routed creates."""
|
|
668
|
+
from general_manager.interface.base_interface import InterfaceBase
|
|
669
|
+
|
|
670
|
+
create = interface.create
|
|
671
|
+
if not router.routers:
|
|
672
|
+
manager.Permission.check_create_permission(payload, manager, creator_id)
|
|
673
|
+
return create(creator_id=creator_id, history_comment=history_comment, **payload)
|
|
674
|
+
|
|
675
|
+
handler = interface.get_capability_handler("create")
|
|
676
|
+
builtin_create = (
|
|
677
|
+
isinstance(handler, OrmCreateCapability)
|
|
678
|
+
and getattr(handler.create, "__func__", None) is OrmCreateCapability.create
|
|
679
|
+
and getattr(create, "__func__", None)
|
|
680
|
+
is getattr(InterfaceBase.create, "__func__", None)
|
|
681
|
+
)
|
|
682
|
+
mutation = interface.get_capability_handler("orm_mutation")
|
|
683
|
+
builtin_save = (
|
|
684
|
+
isinstance(mutation, OrmMutationCapability)
|
|
685
|
+
and getattr(mutation.save_with_history, "__func__", None)
|
|
686
|
+
is OrmMutationCapability.save_with_history
|
|
687
|
+
)
|
|
688
|
+
permission = _RoutedCreatePermission(
|
|
689
|
+
manager, payload, interface, shares_source=builtin_create and builtin_save
|
|
690
|
+
)
|
|
691
|
+
token = _routed_create_check.set(permission)
|
|
692
|
+
try:
|
|
693
|
+
manager.Permission.check_create_permission(payload, manager, creator_id)
|
|
694
|
+
finally:
|
|
695
|
+
_routed_create_check.reset(token)
|
|
696
|
+
|
|
697
|
+
if not builtin_create:
|
|
698
|
+
return create(creator_id=creator_id, history_comment=history_comment, **payload)
|
|
699
|
+
assert isinstance(handler, OrmCreateCapability)
|
|
700
|
+
kwargs = {"creator_id": creator_id, "history_comment": history_comment, **payload}
|
|
701
|
+
return interface._observe_create(
|
|
702
|
+
(),
|
|
703
|
+
kwargs,
|
|
704
|
+
lambda: handler._create(interface, kwargs, permission=permission),
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
|
|
480
708
|
class OrmUpdateCapability(BaseCapability):
|
|
481
709
|
"""Update existing ORM instances."""
|
|
482
710
|
|
|
@@ -31,10 +31,15 @@ class PayloadNormalizer:
|
|
|
31
31
|
self._field_names = {field.name for field in model._meta.get_fields()}
|
|
32
32
|
self._many_to_many_fields = {field.name for field in model._meta.many_to_many}
|
|
33
33
|
self._relation_fields = {
|
|
34
|
-
field.name
|
|
34
|
+
field.name: field
|
|
35
35
|
for field in model._meta.get_fields()
|
|
36
36
|
if isinstance(field, (models.ForeignKey, models.OneToOneField))
|
|
37
37
|
}
|
|
38
|
+
self._relation_aliases = {
|
|
39
|
+
alias: field
|
|
40
|
+
for field in self._relation_fields.values()
|
|
41
|
+
for alias in (field.name, field.attname)
|
|
42
|
+
}
|
|
38
43
|
|
|
39
44
|
# region filter/exclude helpers
|
|
40
45
|
def normalize_filter_kwargs(self, kwargs: PayloadMapping) -> PayloadMapping:
|
|
@@ -139,18 +144,56 @@ class PayloadNormalizer:
|
|
|
139
144
|
remaining_kwargs[key] = value
|
|
140
145
|
return remaining_kwargs, many_kwargs
|
|
141
146
|
|
|
147
|
+
def get_relation_field(self, name: str) -> models.ForeignKey[models.Model] | None:
|
|
148
|
+
"""Resolve an actual forward relation or its raw identifier attribute."""
|
|
149
|
+
return self._relation_aliases.get(name)
|
|
150
|
+
|
|
151
|
+
@staticmethod
|
|
152
|
+
def get_relation_identifier(
|
|
153
|
+
field: models.ForeignKey[models.Model], value: object
|
|
154
|
+
) -> object:
|
|
155
|
+
"""Extract the relation's target-field value, not necessarily its PK."""
|
|
156
|
+
if _is_general_manager_instance(value):
|
|
157
|
+
manager = cast("GeneralManager", value)
|
|
158
|
+
value = (
|
|
159
|
+
manager.identification["id"]
|
|
160
|
+
if field.target_field.primary_key
|
|
161
|
+
else getattr(manager, field.target_field.attname)
|
|
162
|
+
)
|
|
163
|
+
elif isinstance(value, models.Model):
|
|
164
|
+
value = getattr(value, field.target_field.attname)
|
|
165
|
+
return field.target_field.to_python(value)
|
|
166
|
+
|
|
167
|
+
def resolve_relation_aliases(self, kwargs: PayloadMapping) -> PayloadMapping:
|
|
168
|
+
"""Prefer an explicitly supplied raw ID over the same relation object.
|
|
169
|
+
|
|
170
|
+
Only aliases present together in this mapping compete. In particular,
|
|
171
|
+
an explicit raw ID of ``None`` wins too. Callers handling updates must
|
|
172
|
+
apply this to submitted values, not to an old-state overlay.
|
|
173
|
+
"""
|
|
174
|
+
return {
|
|
175
|
+
key: value
|
|
176
|
+
for key, value in kwargs.items()
|
|
177
|
+
if key not in self._relation_fields
|
|
178
|
+
or self._relation_fields[key].attname not in kwargs
|
|
179
|
+
}
|
|
180
|
+
|
|
142
181
|
def normalize_simple_values(self, kwargs: PayloadMapping) -> PayloadMapping:
|
|
143
182
|
"""
|
|
144
183
|
Normalize simple (single-valued) payload entries by converting general-manager objects to their identifier form and adjusting keys.
|
|
145
184
|
|
|
146
|
-
|
|
185
|
+
General-manager values for declared relations use the target field's
|
|
186
|
+
value, including non-primary-key ``to_field`` relations, under the
|
|
187
|
+
relation's raw ID attribute. Other general-manager values retain the
|
|
188
|
+
identifier conversion and ``_id`` suffix behavior. Django model objects
|
|
189
|
+
retain object assignment so Django can validate their type and routing.
|
|
147
190
|
Returns a new mapping and does not mutate `kwargs`. Relation-key
|
|
148
191
|
renaming applies only to forward `ForeignKey` and `OneToOneField`
|
|
149
192
|
names cached from the model metadata. Reverse relations, generic
|
|
150
193
|
relations, and many-to-many fields are not relation-renamed here. If
|
|
151
|
-
both a relation key and its
|
|
152
|
-
|
|
153
|
-
|
|
194
|
+
both a relation key and its raw ID key are explicitly present, the raw
|
|
195
|
+
ID wins independently of iteration order, including when it is None.
|
|
196
|
+
A single supplied alias retains its usual meaning.
|
|
154
197
|
|
|
155
198
|
Parameters:
|
|
156
199
|
kwargs: Mapping of field names to single values to normalize.
|
|
@@ -159,11 +202,15 @@ class PayloadNormalizer:
|
|
|
159
202
|
A new mapping with manager values replaced by their identifiers and keys suffixed with `_id` when appropriate.
|
|
160
203
|
"""
|
|
161
204
|
normalized: PayloadMapping = {}
|
|
162
|
-
for key, value in kwargs.items():
|
|
205
|
+
for key, value in self.resolve_relation_aliases(kwargs).items():
|
|
163
206
|
normalized_key = key
|
|
164
207
|
normalized_value = value
|
|
165
208
|
manager_value = self._maybe_general_manager(value)
|
|
166
|
-
|
|
209
|
+
relation = self.get_relation_field(key)
|
|
210
|
+
if manager_value is not None and relation is not None:
|
|
211
|
+
normalized_key = relation.attname
|
|
212
|
+
normalized_value = self.get_relation_identifier(relation, value)
|
|
213
|
+
elif manager_value is not None and not key.endswith("_id"):
|
|
167
214
|
normalized_key = f"{key}_id"
|
|
168
215
|
normalized_value = manager_value
|
|
169
216
|
elif manager_value is not None:
|