GeneralManager 0.69.2__tar.gz → 0.71.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.69.2/src/GeneralManager.egg-info → generalmanager-0.71.0}/PKG-INFO +1 -1
- {generalmanager-0.69.2 → generalmanager-0.71.0}/pyproject.toml +1 -1
- {generalmanager-0.69.2 → generalmanager-0.71.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/permission.py +2 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_errors.py +8 -3
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_resolvers.py +60 -41
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_search.py +16 -4
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/base_bucket.py +16 -1
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/calculation_bucket.py +95 -5
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/database_bucket.py +17 -1
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/request_bucket.py +12 -1
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/base_permission.py +104 -26
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/manager_based_permission.py +290 -97
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/permission_checks.py +140 -35
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/public_api_registry.py +4 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/LICENSE +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/README.md +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/setup.cfg +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/apps.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/data_change_context.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/conf.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/base_interface.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/logging.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/manager/general_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/py.typed +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/invalidation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/args_to_kwargs.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/make_cache_key.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/none_to_zero.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/tests/test_settings.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.0}/tests/test_urls.py +0 -0
- {generalmanager-0.69.2 → generalmanager-0.71.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.71.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.71.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.71.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
|
|
@@ -16,6 +16,7 @@ __all__ = [
|
|
|
16
16
|
"OverrideManagerPermission",
|
|
17
17
|
"PermissionAuditEvent",
|
|
18
18
|
"PermissionDataManager",
|
|
19
|
+
"PermissionFilterDecision",
|
|
19
20
|
"configure_audit_logger",
|
|
20
21
|
"configure_audit_logger_from_settings",
|
|
21
22
|
"mutation_capability",
|
|
@@ -44,6 +45,7 @@ from general_manager.permission.manager_based_permission import (
|
|
|
44
45
|
)
|
|
45
46
|
from general_manager.permission.audit import PermissionAuditEvent
|
|
46
47
|
from general_manager.permission.permission_data_manager import PermissionDataManager
|
|
48
|
+
from general_manager.permission.permission_checks import PermissionFilterDecision
|
|
47
49
|
from general_manager.permission.audit import configure_audit_logger
|
|
48
50
|
from general_manager.permission.audit import configure_audit_logger_from_settings
|
|
49
51
|
from general_manager.permission.graphql_capabilities import mutation_capability
|
|
@@ -655,7 +655,7 @@ def get_read_permission_filter(
|
|
|
655
655
|
|
|
656
656
|
Returns:
|
|
657
657
|
A ``ReadPermissionPlan`` with ``filters``, ``requires_instance_check``,
|
|
658
|
-
and ``
|
|
658
|
+
``instance_check_reasons``, and ``decision`` fields. ``ReadPermissionPlan`` is an
|
|
659
659
|
internal adapter from ``general_manager.permission.base_permission``, not
|
|
660
660
|
a stable public import path, but generated resolvers rely on these
|
|
661
661
|
fields.
|
|
@@ -677,7 +677,8 @@ def get_read_permission_filter(
|
|
|
677
677
|
``("no_prefilter_backend",)``.
|
|
678
678
|
|
|
679
679
|
Managers without a permission factory receive an empty filter plan and
|
|
680
|
-
do not require instance checks
|
|
680
|
+
do not require instance checks, with an explicit ``"allow_all"``
|
|
681
|
+
decision. This is a default-allow read policy for
|
|
681
682
|
managers that do not define ``Permission``; no additional GraphQL
|
|
682
683
|
permission filtering or per-object read authorization is applied by this
|
|
683
684
|
helper. More generally, ``filters=[]`` with
|
|
@@ -715,4 +716,8 @@ def get_read_permission_filter(
|
|
|
715
716
|
)
|
|
716
717
|
if permission_attribute is not None:
|
|
717
718
|
raise InvalidReadPermissionConfigurationError(generalManagerClass.__name__)
|
|
718
|
-
return ReadPermissionPlan(
|
|
719
|
+
return ReadPermissionPlan(
|
|
720
|
+
filters=[],
|
|
721
|
+
requires_instance_check=False,
|
|
722
|
+
decision="allow_all",
|
|
723
|
+
)
|
{generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/api/graphql_resolvers.py
RENAMED
|
@@ -90,12 +90,17 @@ class UnsupportedExcludeNoneRelationFilterError(ValueError):
|
|
|
90
90
|
|
|
91
91
|
@dataclass(slots=True)
|
|
92
92
|
class ReadAuthorizationResult(Generic[GeneralManagerT]):
|
|
93
|
-
"""Aggregate outcome from GraphQL read prefiltering and row authorization.
|
|
93
|
+
"""Aggregate outcome from GraphQL read prefiltering and row authorization.
|
|
94
|
+
|
|
95
|
+
Counts remain ``None`` when authorization can return a bucket lazily without
|
|
96
|
+
inspecting or counting it. They are populated when a row-level gate actually
|
|
97
|
+
scans candidates; deny-all plans use known zero counts.
|
|
98
|
+
"""
|
|
94
99
|
|
|
95
100
|
queryset: Bucket[GeneralManagerT]
|
|
96
|
-
candidate_count: int
|
|
97
|
-
authorized_count: int
|
|
98
|
-
denied_count: int
|
|
101
|
+
candidate_count: int | None
|
|
102
|
+
authorized_count: int | None
|
|
103
|
+
denied_count: int | None
|
|
99
104
|
backend_shape: str
|
|
100
105
|
requires_instance_check: bool
|
|
101
106
|
instance_check_reasons: tuple[str, ...]
|
|
@@ -266,7 +271,7 @@ def apply_read_authorization(
|
|
|
266
271
|
final row gate runs and an aggregate log event is emitted only if the final
|
|
267
272
|
authorization result still requires instance checks.
|
|
268
273
|
Unrestricted plans that do not require instance checks return the original
|
|
269
|
-
queryset
|
|
274
|
+
queryset without evaluating it to compute counts.
|
|
270
275
|
"""
|
|
271
276
|
permission_plan = get_read_permission_filter(general_manager_class, info)
|
|
272
277
|
backend_shape = get_backend_shape(general_manager_class)
|
|
@@ -275,16 +280,40 @@ def apply_read_authorization(
|
|
|
275
280
|
backend_shape=backend_shape,
|
|
276
281
|
)
|
|
277
282
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
+
if permission_plan.decision == "deny_all":
|
|
284
|
+
return ReadAuthorizationResult(
|
|
285
|
+
queryset=queryset.none(),
|
|
286
|
+
candidate_count=0,
|
|
287
|
+
authorized_count=0,
|
|
288
|
+
denied_count=0,
|
|
289
|
+
backend_shape=backend_shape,
|
|
290
|
+
requires_instance_check=False,
|
|
291
|
+
instance_check_reasons=(),
|
|
292
|
+
)
|
|
293
|
+
|
|
294
|
+
if permission_plan.decision == "allow_all":
|
|
295
|
+
return ReadAuthorizationResult(
|
|
296
|
+
queryset=queryset,
|
|
297
|
+
candidate_count=None,
|
|
298
|
+
authorized_count=None,
|
|
299
|
+
denied_count=None,
|
|
300
|
+
backend_shape=backend_shape,
|
|
301
|
+
requires_instance_check=False,
|
|
302
|
+
instance_check_reasons=(),
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
filtered_queryset: Bucket[GeneralManagerT] | None = queryset
|
|
306
|
+
if (
|
|
307
|
+
not permission_plan.requires_instance_check
|
|
308
|
+
and len(permission_plan.filters) == 1
|
|
309
|
+
and not permission_plan.filters[0].get("filter")
|
|
310
|
+
and not permission_plan.filters[0].get("exclude")
|
|
311
|
+
):
|
|
283
312
|
result = ReadAuthorizationResult(
|
|
284
313
|
queryset=queryset,
|
|
285
|
-
candidate_count=
|
|
286
|
-
authorized_count=
|
|
287
|
-
denied_count=
|
|
314
|
+
candidate_count=None,
|
|
315
|
+
authorized_count=None,
|
|
316
|
+
denied_count=None,
|
|
288
317
|
backend_shape=backend_shape,
|
|
289
318
|
requires_instance_check=False,
|
|
290
319
|
instance_check_reasons=instance_check_reasons,
|
|
@@ -292,7 +321,7 @@ def apply_read_authorization(
|
|
|
292
321
|
return result
|
|
293
322
|
|
|
294
323
|
if permission_plan.filters:
|
|
295
|
-
filtered_queryset =
|
|
324
|
+
filtered_queryset = None
|
|
296
325
|
for permission_filter in permission_plan.filters:
|
|
297
326
|
filter_dict = permission_filter.get("filter", {})
|
|
298
327
|
exclude_dict = permission_filter.get("exclude", {})
|
|
@@ -300,7 +329,10 @@ def apply_read_authorization(
|
|
|
300
329
|
qs_perm = queryset
|
|
301
330
|
else:
|
|
302
331
|
qs_perm = queryset.filter(**filter_dict).exclude(**exclude_dict)
|
|
303
|
-
filtered_queryset =
|
|
332
|
+
filtered_queryset = (
|
|
333
|
+
qs_perm if filtered_queryset is None else filtered_queryset | qs_perm
|
|
334
|
+
)
|
|
335
|
+
assert filtered_queryset is not None
|
|
304
336
|
|
|
305
337
|
result = filter_queryset_by_read_permission(
|
|
306
338
|
filtered_queryset,
|
|
@@ -332,19 +364,17 @@ def filter_queryset_by_read_permission(
|
|
|
332
364
|
Apply final row-level read authorization to a bucket.
|
|
333
365
|
|
|
334
366
|
When an instance gate is not required, or the manager has no Permission
|
|
335
|
-
class, the original queryset is returned
|
|
336
|
-
Otherwise each candidate is checked with ``can_read_instance()
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
instances.
|
|
367
|
+
class, the original queryset is returned without eagerly computing counts.
|
|
368
|
+
Otherwise each candidate is checked with ``can_read_instance()`` and the
|
|
369
|
+
originating bucket reconstructs the exact authorized instance subset using
|
|
370
|
+
its backend-native representation.
|
|
340
371
|
"""
|
|
341
372
|
if not requires_instance_check:
|
|
342
|
-
candidate_count = len(queryset)
|
|
343
373
|
return ReadAuthorizationResult(
|
|
344
374
|
queryset=queryset,
|
|
345
|
-
candidate_count=
|
|
346
|
-
authorized_count=
|
|
347
|
-
denied_count=
|
|
375
|
+
candidate_count=None,
|
|
376
|
+
authorized_count=None,
|
|
377
|
+
denied_count=None,
|
|
348
378
|
backend_shape=backend_shape,
|
|
349
379
|
requires_instance_check=False,
|
|
350
380
|
instance_check_reasons=instance_check_reasons,
|
|
@@ -354,36 +384,25 @@ def filter_queryset_by_read_permission(
|
|
|
354
384
|
general_manager_class, "Permission", None
|
|
355
385
|
)
|
|
356
386
|
if PermissionClass is None:
|
|
357
|
-
candidate_count = len(queryset)
|
|
358
387
|
return ReadAuthorizationResult(
|
|
359
388
|
queryset=queryset,
|
|
360
|
-
candidate_count=
|
|
361
|
-
authorized_count=
|
|
362
|
-
denied_count=
|
|
389
|
+
candidate_count=None,
|
|
390
|
+
authorized_count=None,
|
|
391
|
+
denied_count=None,
|
|
363
392
|
backend_shape=backend_shape,
|
|
364
393
|
requires_instance_check=False,
|
|
365
394
|
instance_check_reasons=instance_check_reasons,
|
|
366
395
|
)
|
|
367
396
|
|
|
368
|
-
authorized_ids: list[object] = []
|
|
369
397
|
authorized_instances: list[GeneralManagerT] = []
|
|
370
398
|
candidate_count = 0
|
|
371
399
|
for instance in queryset:
|
|
372
400
|
candidate_count += 1
|
|
373
401
|
if PermissionClass(instance, info.context.user).can_read_instance():
|
|
374
|
-
|
|
375
|
-
instance_id = identification.get("id")
|
|
376
|
-
if instance_id is None:
|
|
377
|
-
authorized_instances.append(instance)
|
|
378
|
-
else:
|
|
379
|
-
authorized_ids.append(instance_id)
|
|
402
|
+
authorized_instances.append(instance)
|
|
380
403
|
|
|
381
|
-
authorized_queryset = (
|
|
382
|
-
|
|
383
|
-
)
|
|
384
|
-
for instance in authorized_instances:
|
|
385
|
-
authorized_queryset = authorized_queryset | instance
|
|
386
|
-
authorized_count = len(authorized_ids) + len(authorized_instances)
|
|
404
|
+
authorized_queryset = queryset.with_instances(authorized_instances)
|
|
405
|
+
authorized_count = len(authorized_instances)
|
|
387
406
|
return ReadAuthorizationResult(
|
|
388
407
|
queryset=authorized_queryset,
|
|
389
408
|
candidate_count=candidate_count,
|
|
@@ -382,6 +382,11 @@ def passes_permission_filters(
|
|
|
382
382
|
"""
|
|
383
383
|
if permission_plan is None:
|
|
384
384
|
permission_plan = get_read_permission_filter(instance.__class__, info)
|
|
385
|
+
decision = getattr(permission_plan, "decision", "conditional")
|
|
386
|
+
if decision == "allow_all":
|
|
387
|
+
return True
|
|
388
|
+
if decision == "deny_all":
|
|
389
|
+
return False
|
|
385
390
|
permission_filters = permission_plan.filters
|
|
386
391
|
if not permission_filters:
|
|
387
392
|
return can_read_instance(instance, info)
|
|
@@ -1046,14 +1051,21 @@ def register_search_query(
|
|
|
1046
1051
|
for manager_class in manager_classes:
|
|
1047
1052
|
type_label = manager_class.__name__
|
|
1048
1053
|
permission_plan = get_read_permission_filter(manager_class, info)
|
|
1054
|
+
decision = getattr(permission_plan, "decision", "conditional")
|
|
1055
|
+
if decision == "deny_all":
|
|
1056
|
+
continue
|
|
1049
1057
|
backend_shape = get_backend_shape(manager_class)
|
|
1050
1058
|
instance_check_reasons = resolve_instance_check_reasons(
|
|
1051
1059
|
permission_plan,
|
|
1052
1060
|
backend_shape=backend_shape,
|
|
1053
1061
|
)
|
|
1054
|
-
filter_groups =
|
|
1055
|
-
parsed_filters
|
|
1056
|
-
|
|
1062
|
+
filter_groups = (
|
|
1063
|
+
parsed_filters or None
|
|
1064
|
+
if decision == "allow_all"
|
|
1065
|
+
else merge_permission_filters(
|
|
1066
|
+
parsed_filters,
|
|
1067
|
+
permission_plan.filters,
|
|
1068
|
+
)
|
|
1057
1069
|
)
|
|
1058
1070
|
total_hits_for_manager = 0
|
|
1059
1071
|
candidate_hits_for_manager = 0
|
|
@@ -1127,7 +1139,7 @@ def register_search_query(
|
|
|
1127
1139
|
total += total_hits_for_manager
|
|
1128
1140
|
if not manager_total_is_exact:
|
|
1129
1141
|
total_is_exact = False
|
|
1130
|
-
if permission_plan.requires_instance_check:
|
|
1142
|
+
if decision == "conditional" and permission_plan.requires_instance_check:
|
|
1131
1143
|
logger.info(
|
|
1132
1144
|
"graphql read authorization summary",
|
|
1133
1145
|
context={
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
from abc import ABC, abstractmethod
|
|
5
|
-
from collections.abc import Hashable, Mapping
|
|
5
|
+
from collections.abc import Hashable, Iterable, Mapping
|
|
6
6
|
from typing import (
|
|
7
7
|
Generator,
|
|
8
8
|
TYPE_CHECKING,
|
|
@@ -437,3 +437,18 @@ class Bucket(ABC, Generic[GeneralManagerType]):
|
|
|
437
437
|
"The 'none' method is not implemented in the base Bucket class. "
|
|
438
438
|
"Subclasses should implement this method to return an empty bucket."
|
|
439
439
|
)
|
|
440
|
+
|
|
441
|
+
def with_instances(
|
|
442
|
+
self,
|
|
443
|
+
instances: Iterable[GeneralManagerType],
|
|
444
|
+
) -> Bucket[GeneralManagerType]:
|
|
445
|
+
"""Return a bucket containing exactly the supplied manager instances.
|
|
446
|
+
|
|
447
|
+
Callers provide instances in source iteration order and implementations
|
|
448
|
+
retain that order. Backends may override this compatibility fallback to
|
|
449
|
+
avoid repeated unions or unsupported lookups.
|
|
450
|
+
"""
|
|
451
|
+
subset = self.none()
|
|
452
|
+
for instance in instances:
|
|
453
|
+
subset = subset | instance
|
|
454
|
+
return subset
|
{generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/calculation_bucket.py
RENAMED
|
@@ -219,6 +219,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
219
219
|
self._excludes = parse_filters(self.exclude_definitions, possible_values)
|
|
220
220
|
|
|
221
221
|
self._data: list[Combination] | None = None
|
|
222
|
+
self._allowed_identifications: list[Combination] | None = None
|
|
222
223
|
self.sort_key = sort_key
|
|
223
224
|
self.reverse = reverse
|
|
224
225
|
self._effective_search_date = current_as_of_date()
|
|
@@ -251,6 +252,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
251
252
|
reverse,
|
|
252
253
|
)
|
|
253
254
|
bucket._effective_search_date = self._effective_search_date
|
|
255
|
+
if self._allowed_identifications is not None:
|
|
256
|
+
bucket._allowed_identifications = [
|
|
257
|
+
dict(identification) for identification in self._allowed_identifications
|
|
258
|
+
]
|
|
254
259
|
return bucket
|
|
255
260
|
|
|
256
261
|
def __eq__(self, other: object) -> bool:
|
|
@@ -292,6 +297,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
292
297
|
),
|
|
293
298
|
{
|
|
294
299
|
"data": self._data,
|
|
300
|
+
"allowed_identifications": self._allowed_identifications,
|
|
295
301
|
"effective_search_date": self._effective_search_date,
|
|
296
302
|
},
|
|
297
303
|
)
|
|
@@ -307,6 +313,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
307
313
|
None
|
|
308
314
|
"""
|
|
309
315
|
self._data = cast(list[Combination] | None, state.get("data"))
|
|
316
|
+
self._allowed_identifications = cast(
|
|
317
|
+
list[Combination] | None,
|
|
318
|
+
state.get("allowed_identifications"),
|
|
319
|
+
)
|
|
310
320
|
self._effective_search_date = cast(
|
|
311
321
|
"datetime | None", state.get("effective_search_date")
|
|
312
322
|
)
|
|
@@ -360,12 +370,29 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
360
370
|
}
|
|
361
371
|
|
|
362
372
|
other._ensure_as_of_compatible()
|
|
363
|
-
|
|
373
|
+
combined = self._derive(
|
|
364
374
|
filter_definitions=combined_filters,
|
|
365
375
|
exclude_definitions=combined_excludes,
|
|
366
376
|
sort_key=None,
|
|
367
377
|
reverse=False,
|
|
368
378
|
)
|
|
379
|
+
if self._allowed_identifications is None:
|
|
380
|
+
if other._allowed_identifications is not None:
|
|
381
|
+
combined._allowed_identifications = [
|
|
382
|
+
dict(identification)
|
|
383
|
+
for identification in other._allowed_identifications
|
|
384
|
+
]
|
|
385
|
+
elif other._allowed_identifications is not None:
|
|
386
|
+
other_allowed_keys = {
|
|
387
|
+
freeze_bucket_index_value(identification)
|
|
388
|
+
for identification in other._allowed_identifications
|
|
389
|
+
}
|
|
390
|
+
combined._allowed_identifications = [
|
|
391
|
+
dict(identification)
|
|
392
|
+
for identification in self._allowed_identifications
|
|
393
|
+
if freeze_bucket_index_value(identification) in other_allowed_keys
|
|
394
|
+
]
|
|
395
|
+
return combined
|
|
369
396
|
|
|
370
397
|
def __str__(self) -> str:
|
|
371
398
|
"""
|
|
@@ -431,11 +458,22 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
431
458
|
sorted_filters["input_excludes"],
|
|
432
459
|
snapshot_iterables=snapshot_iterables,
|
|
433
460
|
)
|
|
434
|
-
|
|
461
|
+
allowed_identification_keys = None
|
|
462
|
+
if self._allowed_identifications is not None:
|
|
463
|
+
allowed_identification_keys = {
|
|
464
|
+
freeze_bucket_index_value(identification)
|
|
465
|
+
for identification in self._allowed_identifications
|
|
466
|
+
}
|
|
467
|
+
if (
|
|
468
|
+
sorted_filters["prop_filters"]
|
|
469
|
+
or sorted_filters["prop_excludes"]
|
|
470
|
+
or allowed_identification_keys is not None
|
|
471
|
+
):
|
|
435
472
|
preview_iterator = self._iter_prop_filtered_identifications(
|
|
436
473
|
preview_iterator,
|
|
437
474
|
sorted_filters["prop_filters"],
|
|
438
475
|
sorted_filters["prop_excludes"],
|
|
476
|
+
allowed_identification_keys,
|
|
439
477
|
)
|
|
440
478
|
preview = list(islice(preview_iterator, limit + 1))
|
|
441
479
|
|
|
@@ -656,6 +694,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
656
694
|
self._manager_class,
|
|
657
695
|
freeze_bucket_index_value(self.filter_definitions),
|
|
658
696
|
freeze_bucket_index_value(self.exclude_definitions),
|
|
697
|
+
freeze_bucket_index_value(self._allowed_identifications),
|
|
659
698
|
self._normalized_sort_key(),
|
|
660
699
|
self.reverse,
|
|
661
700
|
)
|
|
@@ -738,6 +777,21 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
738
777
|
sorted_filters["input_filters"],
|
|
739
778
|
sorted_filters["input_excludes"],
|
|
740
779
|
)
|
|
780
|
+
manager_combinations: list[GeneralManagerType] | None = None
|
|
781
|
+
if self._allowed_identifications is not None:
|
|
782
|
+
allowed_identification_keys = {
|
|
783
|
+
freeze_bucket_index_value(identification)
|
|
784
|
+
for identification in self._allowed_identifications
|
|
785
|
+
}
|
|
786
|
+
manager_combinations = [
|
|
787
|
+
manager
|
|
788
|
+
for manager in self._manager_combinations(current_combinations)
|
|
789
|
+
if freeze_bucket_index_value(manager.identification)
|
|
790
|
+
in allowed_identification_keys
|
|
791
|
+
]
|
|
792
|
+
current_combinations = self._manager_identifications(
|
|
793
|
+
manager_combinations
|
|
794
|
+
)
|
|
741
795
|
sort_key = self._normalized_sort_key()
|
|
742
796
|
needs_manager_access = (
|
|
743
797
|
bool(sorted_filters["prop_filters"])
|
|
@@ -746,9 +800,10 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
746
800
|
)
|
|
747
801
|
|
|
748
802
|
if needs_manager_access:
|
|
749
|
-
manager_combinations
|
|
750
|
-
|
|
751
|
-
|
|
803
|
+
if manager_combinations is None:
|
|
804
|
+
manager_combinations = self._manager_combinations(
|
|
805
|
+
current_combinations
|
|
806
|
+
)
|
|
752
807
|
manager_combinations = self._filter_prop_combinations(
|
|
753
808
|
manager_combinations,
|
|
754
809
|
sorted_filters["prop_filters"],
|
|
@@ -1006,6 +1061,7 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
1006
1061
|
combinations: Iterable[Combination],
|
|
1007
1062
|
prop_filters: ParsedFilters,
|
|
1008
1063
|
prop_excludes: ParsedFilters,
|
|
1064
|
+
allowed_identification_keys: set[Hashable] | None = None,
|
|
1009
1065
|
) -> Generator[Combination, None, None]:
|
|
1010
1066
|
"""
|
|
1011
1067
|
Lazily apply property filters and yield manager identifications.
|
|
@@ -1016,6 +1072,12 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
1016
1072
|
"""
|
|
1017
1073
|
for combo in combinations:
|
|
1018
1074
|
manager = self._manager_class(**combo)
|
|
1075
|
+
if (
|
|
1076
|
+
allowed_identification_keys is not None
|
|
1077
|
+
and freeze_bucket_index_value(manager.identification)
|
|
1078
|
+
not in allowed_identification_keys
|
|
1079
|
+
):
|
|
1080
|
+
continue
|
|
1019
1081
|
if self._filter_prop_combinations([manager], prop_filters, prop_excludes):
|
|
1020
1082
|
yield manager.identification
|
|
1021
1083
|
|
|
@@ -1222,4 +1284,32 @@ class CalculationBucket(Bucket[GeneralManagerType]):
|
|
|
1222
1284
|
own.exclude_definitions = {}
|
|
1223
1285
|
own._filters = {}
|
|
1224
1286
|
own._excludes = {}
|
|
1287
|
+
own._allowed_identifications = []
|
|
1225
1288
|
return own
|
|
1289
|
+
|
|
1290
|
+
def with_instances(
|
|
1291
|
+
self,
|
|
1292
|
+
instances: Iterable[GeneralManagerType],
|
|
1293
|
+
) -> CalculationBucket[GeneralManagerType]:
|
|
1294
|
+
"""Return a materialized subset using declared input identifications."""
|
|
1295
|
+
self._ensure_as_of_compatible()
|
|
1296
|
+
from general_manager.manager.general_manager import GeneralManager
|
|
1297
|
+
|
|
1298
|
+
identifications: list[Combination] = []
|
|
1299
|
+
for instance in instances:
|
|
1300
|
+
if instance.__class__ != self._manager_class:
|
|
1301
|
+
raise IncompatibleBucketTypeError(self.__class__, type(instance))
|
|
1302
|
+
if isinstance(instance, GeneralManager):
|
|
1303
|
+
instance._ensure_as_of_compatible()
|
|
1304
|
+
identifications.append(dict(instance.identification))
|
|
1305
|
+
subset = self._derive(
|
|
1306
|
+
filter_definitions=self.filter_definitions.copy(),
|
|
1307
|
+
exclude_definitions=self.exclude_definitions.copy(),
|
|
1308
|
+
sort_key=self.sort_key,
|
|
1309
|
+
reverse=self.reverse,
|
|
1310
|
+
)
|
|
1311
|
+
subset._allowed_identifications = [
|
|
1312
|
+
dict(identification) for identification in identifications
|
|
1313
|
+
]
|
|
1314
|
+
subset._data = identifications
|
|
1315
|
+
return subset
|
{generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/database_bucket.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Database-backed bucket implementation for GeneralManager collections."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
|
-
from collections.abc import Callable, Hashable, Mapping
|
|
4
|
+
from collections.abc import Callable, Hashable, Iterable, Mapping
|
|
5
5
|
from datetime import date, datetime
|
|
6
6
|
from typing import TYPE_CHECKING, Generator, TypeVar, cast
|
|
7
7
|
|
|
@@ -1533,3 +1533,19 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
1533
1533
|
own._query_signature_cache = _QUERY_SIGNATURE_NOT_COMPUTED
|
|
1534
1534
|
own._trusted_query_signature = None
|
|
1535
1535
|
return own
|
|
1536
|
+
|
|
1537
|
+
def with_instances(
|
|
1538
|
+
self,
|
|
1539
|
+
instances: Iterable[GeneralManagerType],
|
|
1540
|
+
) -> DatabaseBucket[GeneralManagerType]:
|
|
1541
|
+
"""Return a source-ordered subset selected by manager primary keys."""
|
|
1542
|
+
self._ensure_as_of_compatible()
|
|
1543
|
+
ids: list[object] = []
|
|
1544
|
+
for instance in instances:
|
|
1545
|
+
if not isinstance(instance, GeneralManager) or (
|
|
1546
|
+
instance.__class__ != self._manager_class
|
|
1547
|
+
):
|
|
1548
|
+
raise DatabaseBucketTypeMismatchError(self.__class__, type(instance))
|
|
1549
|
+
instance._ensure_as_of_compatible()
|
|
1550
|
+
ids.append(instance.identification["id"])
|
|
1551
|
+
return self.filter(id__in=ids) if ids else self.none()
|
{generalmanager-0.69.2 → generalmanager-0.71.0}/src/general_manager/bucket/request_bucket.py
RENAMED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from collections.abc import Generator, Hashable, Mapping
|
|
5
|
+
from collections.abc import Generator, Hashable, Iterable, Mapping
|
|
6
6
|
from typing import TYPE_CHECKING, Protocol, cast
|
|
7
7
|
|
|
8
8
|
from general_manager.bucket.base_bucket import Bucket, GeneralManagerType
|
|
@@ -452,6 +452,17 @@ class RequestBucket(Bucket[GeneralManagerType]):
|
|
|
452
452
|
"""Return an empty materialized bucket preserving the operation name."""
|
|
453
453
|
return self._from_items(tuple())
|
|
454
454
|
|
|
455
|
+
def with_instances(
|
|
456
|
+
self,
|
|
457
|
+
instances: Iterable[GeneralManagerType],
|
|
458
|
+
) -> "RequestBucket[GeneralManagerType]":
|
|
459
|
+
"""Return a materialized subset without re-executing the request plan."""
|
|
460
|
+
items = tuple(instances)
|
|
461
|
+
for instance in items:
|
|
462
|
+
if not isinstance(instance, self._manager_class):
|
|
463
|
+
raise RequestBucketTypeMismatchError(self.__class__, type(instance))
|
|
464
|
+
return self._from_items(items)
|
|
465
|
+
|
|
455
466
|
@property
|
|
456
467
|
def operation_name(self) -> str:
|
|
457
468
|
"""Return the query operation name preserved on this bucket.
|