GeneralManager 0.89.2__tar.gz → 0.90.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.
- {generalmanager-0.89.2/src/GeneralManager.egg-info → generalmanager-0.90.0}/PKG-INFO +1 -1
- {generalmanager-0.89.2 → generalmanager-0.90.0}/pyproject.toml +1 -1
- {generalmanager-0.89.2 → generalmanager-0.90.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/GeneralManager.egg-info/SOURCES.txt +2 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql.py +42 -4
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_query_permissions.py +53 -6
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_resolvers.py +16 -1
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/base_interface.py +12 -3
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/mutations.py +242 -14
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +54 -7
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/request/__init__.py +20 -5
- generalmanager-0.90.0/src/general_manager/interface/capabilities/request/relation_inputs.py +249 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/manager/general_manager.py +22 -5
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/manager_based_permission.py +142 -18
- generalmanager-0.90.0/src/general_manager/permission/permission_data_manager.py +443 -0
- generalmanager-0.90.0/src/general_manager/permission/relation_aliases.py +58 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/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.90.0}/LICENSE +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/README.md +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/setup.cfg +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_filter_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_groups.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_identifiers.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_ordering.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_output.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_type.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_units.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_value_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/mutation_controls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/apps.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/_materialized_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/_ordering.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/database_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/excel_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/projection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/_dependency_graph.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/batch_refresh.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/cache/transaction_barrier.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/audit_identity.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/datasets/planned_orchestration.yaml +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/execution.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/judges/result_set.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/outcomes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/graphql_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/mutation_inputs.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/action_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/binding_diagnostics.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/budget.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/calculation_scope.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/calculations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/catalog.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/category_binding.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/choice_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/clarification.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/conversion.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/cross_query.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/deferred_calculations.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/deferred_schema.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/events.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/evidence.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/evidence_selection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/group_actions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/planner.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/planner_context.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/provider_calls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/resolver.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/scheduler.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/schema_projection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/selector_clarification.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/selector_question.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/synthesis.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/planned/validation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/schema_inspection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/turns.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/conf.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/bundles/excel.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/calculation/input_resolution.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/excel/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/bulk.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/create_many.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/history_query.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm_utils/collection_probes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/orm_utils/update_state.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/excel.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/excel_store.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/excel_workbook.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/excel.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/unit_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/logging.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/sync_read_only.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/manager/bulk_create.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/0012_chat_context_watermarks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/py.typed +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/identity.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/projection.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/_args_to_kwargs.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/_cache_key_encoder.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/_make_cache_key.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/_none_to_zero.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/executable_contract.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/tests/test_settings.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/tests/test_urls.py +0 -0
- {generalmanager-0.89.2 → generalmanager-0.90.0}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.90.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.
|
|
7
|
+
version = "0.90.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.
|
|
3
|
+
Version: 0.90.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
|
|
@@ -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
|
|
@@ -246,6 +246,23 @@ def _contains_measurement(annotation: object) -> bool:
|
|
|
246
246
|
return any(_contains_measurement(argument) for argument in get_args(annotation))
|
|
247
247
|
|
|
248
248
|
|
|
249
|
+
class InvalidGraphQLMutationDefaultError(TypeError):
|
|
250
|
+
"""Raised when the global generated CRUD default is not boolean."""
|
|
251
|
+
|
|
252
|
+
def __init__(self) -> None:
|
|
253
|
+
super().__init__("GRAPHQL_MUTATIONS_ENABLED must be a bool.")
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
class InvalidGraphQLMutationConfigurationError(TypeError):
|
|
257
|
+
"""Raised when a manager's generated CRUD allowlist is invalid."""
|
|
258
|
+
|
|
259
|
+
def __init__(self, manager_name: str) -> None:
|
|
260
|
+
super().__init__(
|
|
261
|
+
f"{manager_name}.__graphql_mutations__ must be a set or frozenset "
|
|
262
|
+
"containing only 'create', 'update', and 'delete'."
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
|
|
249
266
|
class GraphQLOutputTypeError(ValueError):
|
|
250
267
|
"""Raised when an output declaration cannot be registered safely."""
|
|
251
268
|
|
|
@@ -724,7 +741,14 @@ class GraphQL:
|
|
|
724
741
|
registering anything. Otherwise, it generates create/update/delete
|
|
725
742
|
mutation classes when the manager's Interface advertises support for the
|
|
726
743
|
corresponding operation: either by overriding the `InterfaceBase` method
|
|
727
|
-
or by listing the operation in `Interface.get_capabilities()`.
|
|
744
|
+
or by listing the operation in `Interface.get_capabilities()`. The
|
|
745
|
+
manager's `__graphql_mutations__` set or frozenset must also include that
|
|
746
|
+
operation. When omitted, the global GRAPHQL_MUTATIONS_ENABLED setting
|
|
747
|
+
defaults to True (all three operations); False hides all. Explicit
|
|
748
|
+
inherited allowlists override that default. An empty set
|
|
749
|
+
disables generated CRUD without changing Python writes, permissions,
|
|
750
|
+
queries, or separately registered custom mutations. Invalid allowlists
|
|
751
|
+
raise `TypeError` before mutation registration changes. Each
|
|
728
752
|
successfully generated mutation is stored on the class-level registry
|
|
729
753
|
(`_mutations`) under the names `create<ManagerName>`,
|
|
730
754
|
`update<ManagerName>`, and `delete<ManagerName>`. If a mutation factory
|
|
@@ -741,6 +765,20 @@ class GraphQL:
|
|
|
741
765
|
if not interface_cls:
|
|
742
766
|
return None
|
|
743
767
|
|
|
768
|
+
supported_mutations = {"create", "update", "delete"}
|
|
769
|
+
global_default = get_setting("GRAPHQL_MUTATIONS_ENABLED", True)
|
|
770
|
+
if not isinstance(global_default, bool):
|
|
771
|
+
raise InvalidGraphQLMutationDefaultError()
|
|
772
|
+
graphql_mutations = getattr(
|
|
773
|
+
generalManagerClass,
|
|
774
|
+
"__graphql_mutations__",
|
|
775
|
+
supported_mutations if global_default else frozenset(),
|
|
776
|
+
)
|
|
777
|
+
if not isinstance(graphql_mutations, (set, frozenset)) or not (
|
|
778
|
+
graphql_mutations <= supported_mutations
|
|
779
|
+
):
|
|
780
|
+
raise InvalidGraphQLMutationConfigurationError(generalManagerClass.__name__)
|
|
781
|
+
|
|
744
782
|
default_return_values = {
|
|
745
783
|
"success": graphene.Boolean(),
|
|
746
784
|
generalManagerClass.__name__: graphene.Field(
|
|
@@ -765,7 +803,7 @@ class GraphQL:
|
|
|
765
803
|
method_overridden = base_method.__code__ != method.__code__
|
|
766
804
|
return method_overridden or op_name in capabilities
|
|
767
805
|
|
|
768
|
-
if _supports("create", "create"):
|
|
806
|
+
if "create" in graphql_mutations and _supports("create", "create"):
|
|
769
807
|
create_name = f"create{generalManagerClass.__name__}"
|
|
770
808
|
create_mutation = cls.generate_create_mutation_class(
|
|
771
809
|
generalManagerClass, default_return_values
|
|
@@ -780,7 +818,7 @@ class GraphQL:
|
|
|
780
818
|
},
|
|
781
819
|
)
|
|
782
820
|
|
|
783
|
-
if _supports("update", "update"):
|
|
821
|
+
if "update" in graphql_mutations and _supports("update", "update"):
|
|
784
822
|
update_name = f"update{generalManagerClass.__name__}"
|
|
785
823
|
update_mutation = cls.generate_update_mutation_class(
|
|
786
824
|
generalManagerClass, default_return_values
|
|
@@ -795,7 +833,7 @@ class GraphQL:
|
|
|
795
833
|
},
|
|
796
834
|
)
|
|
797
835
|
|
|
798
|
-
if _supports("delete", "delete"):
|
|
836
|
+
if "delete" in graphql_mutations and _supports("delete", "delete"):
|
|
799
837
|
delete_name = f"delete{generalManagerClass.__name__}"
|
|
800
838
|
delete_mutation = cls.generate_delete_mutation_class(
|
|
801
839
|
generalManagerClass, default_return_values
|
{generalmanager-0.89.2 → generalmanager-0.90.0}/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.90.0}/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.90.0}/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
|
|