GeneralManager 0.60.0__tar.gz → 0.60.1__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.60.0/src/GeneralManager.egg-info → generalmanager-0.60.1}/PKG-INFO +1 -1
- {generalmanager-0.60.0 → generalmanager-0.60.1}/pyproject.toml +1 -1
- {generalmanager-0.60.0 → generalmanager-0.60.1/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/database_bucket.py +224 -16
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/cache_tracker.py +12 -4
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_cache.py +15 -5
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_matching.py +66 -5
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_shards.py +2 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/run_context.py +167 -1
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/signals.py +7 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/base_interface.py +74 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/support.py +160 -5
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +195 -9
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/general_manager.py +85 -12
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/meta.py +62 -4
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/measurement/measurement.py +118 -25
- generalmanager-0.60.1/src/general_manager/utils/make_cache_key.py +114 -0
- generalmanager-0.60.0/src/general_manager/utils/make_cache_key.py +0 -43
- {generalmanager-0.60.0 → generalmanager-0.60.1}/LICENSE +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/README.md +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/setup.cfg +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_resolvers.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/apps.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_index.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/conf.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/logging.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/py.typed +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/args_to_kwargs.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/none_to_zero.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/tests/test_settings.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/tests/test_urls.py +0 -0
- {generalmanager-0.60.0 → generalmanager-0.60.1}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.60.
|
|
3
|
+
Version: 0.60.1
|
|
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.60.
|
|
7
|
+
version = "0.60.1"
|
|
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.60.
|
|
3
|
+
Version: 0.60.1
|
|
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
|
{generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/bucket/database_bucket.py
RENAMED
|
@@ -27,6 +27,9 @@ QueryAnnotationCallable = Callable[
|
|
|
27
27
|
models.QuerySet[models.Model],
|
|
28
28
|
]
|
|
29
29
|
MAX_RUN_SCOPED_BUCKET_RESULT_ROWS = 1000
|
|
30
|
+
_QUERY_SIGNATURE_NOT_COMPUTED = object()
|
|
31
|
+
_FIRST_ROW_CACHE_MISS = object()
|
|
32
|
+
_FIRST_ROW_CACHE_NONE = object()
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
class DatabaseBucketTypeMismatchError(TypeError):
|
|
@@ -251,6 +254,79 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
251
254
|
self._sort_keys = sort_keys
|
|
252
255
|
self._sort_reverse = sort_reverse
|
|
253
256
|
self._run_scoped_cacheable = run_scoped_cacheable
|
|
257
|
+
self._query_signature_cache: tuple[Hashable, ...] | None | object = (
|
|
258
|
+
_QUERY_SIGNATURE_NOT_COMPUTED
|
|
259
|
+
)
|
|
260
|
+
self._trusted_query_signature: Hashable | None = None
|
|
261
|
+
|
|
262
|
+
def _set_trusted_query_signature(self, signature: Hashable | None) -> None:
|
|
263
|
+
"""Set an internal non-SQL signature for framework-built querysets."""
|
|
264
|
+
self._trusted_query_signature = signature
|
|
265
|
+
self._query_signature_cache = _QUERY_SIGNATURE_NOT_COMPUTED
|
|
266
|
+
|
|
267
|
+
def _copy_for_run_context_reuse(self) -> DatabaseBucket[GeneralManagerType]:
|
|
268
|
+
"""Return an unexposed bucket copy that reuses the same trusted queryset."""
|
|
269
|
+
|
|
270
|
+
bucket = self.__class__(
|
|
271
|
+
self._data,
|
|
272
|
+
self._manager_class,
|
|
273
|
+
self.filters,
|
|
274
|
+
self.excludes,
|
|
275
|
+
search_date=self._search_date,
|
|
276
|
+
sort_keys=self._sort_keys,
|
|
277
|
+
sort_reverse=self._sort_reverse,
|
|
278
|
+
run_scoped_cacheable=self._run_scoped_cacheable,
|
|
279
|
+
)
|
|
280
|
+
bucket._set_trusted_query_signature(self._trusted_query_signature)
|
|
281
|
+
return bucket
|
|
282
|
+
|
|
283
|
+
@staticmethod
|
|
284
|
+
def _freeze_trusted_signature_payload(value: object) -> Hashable:
|
|
285
|
+
if isinstance(value, Mapping):
|
|
286
|
+
return tuple(
|
|
287
|
+
(
|
|
288
|
+
str(key),
|
|
289
|
+
DatabaseBucket._freeze_trusted_signature_payload(item_value),
|
|
290
|
+
)
|
|
291
|
+
for key, item_value in sorted(
|
|
292
|
+
value.items(),
|
|
293
|
+
key=lambda item: str(item[0]),
|
|
294
|
+
)
|
|
295
|
+
)
|
|
296
|
+
if isinstance(value, (list, tuple)):
|
|
297
|
+
return tuple(
|
|
298
|
+
DatabaseBucket._freeze_trusted_signature_payload(item) for item in value
|
|
299
|
+
)
|
|
300
|
+
if isinstance(value, (set, frozenset)):
|
|
301
|
+
return tuple(
|
|
302
|
+
sorted(
|
|
303
|
+
(
|
|
304
|
+
DatabaseBucket._freeze_trusted_signature_payload(item)
|
|
305
|
+
for item in value
|
|
306
|
+
),
|
|
307
|
+
key=repr,
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
if isinstance(value, models.Model):
|
|
311
|
+
return ("model", value.__class__, value.pk)
|
|
312
|
+
try:
|
|
313
|
+
hash(value)
|
|
314
|
+
except TypeError:
|
|
315
|
+
return ("serialized", serialize_dependency_identifier(value))
|
|
316
|
+
return value
|
|
317
|
+
|
|
318
|
+
def _trusted_query_signature_with(
|
|
319
|
+
self,
|
|
320
|
+
operation: str,
|
|
321
|
+
kwargs: Mapping[str, object],
|
|
322
|
+
) -> Hashable | None:
|
|
323
|
+
if self._trusted_query_signature is None:
|
|
324
|
+
return None
|
|
325
|
+
return (
|
|
326
|
+
self._trusted_query_signature,
|
|
327
|
+
operation,
|
|
328
|
+
self._freeze_trusted_signature_payload(kwargs),
|
|
329
|
+
)
|
|
254
330
|
|
|
255
331
|
def __reduce__(self) -> str | tuple[object, ...]:
|
|
256
332
|
"""
|
|
@@ -365,27 +441,50 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
365
441
|
tuple[Hashable, ...] | None: Cache key components for equivalent
|
|
366
442
|
queryset results, or ``None`` when reuse should be bypassed.
|
|
367
443
|
"""
|
|
444
|
+
if self._query_signature_cache is not _QUERY_SIGNATURE_NOT_COMPUTED:
|
|
445
|
+
return cast(tuple[Hashable, ...] | None, self._query_signature_cache)
|
|
368
446
|
if not self._run_scoped_cacheable:
|
|
447
|
+
self._query_signature_cache = None
|
|
369
448
|
return None
|
|
449
|
+
if self._trusted_query_signature is not None:
|
|
450
|
+
signature = (
|
|
451
|
+
self._manager_class,
|
|
452
|
+
self._data.model,
|
|
453
|
+
self._data.db,
|
|
454
|
+
"trusted",
|
|
455
|
+
self._trusted_query_signature,
|
|
456
|
+
self._search_date,
|
|
457
|
+
self._sort_keys,
|
|
458
|
+
self._sort_reverse,
|
|
459
|
+
)
|
|
460
|
+
self._query_signature_cache = signature
|
|
461
|
+
return signature
|
|
370
462
|
query = self._data.query
|
|
371
463
|
if not isinstance(query, Query):
|
|
464
|
+
self._query_signature_cache = None
|
|
372
465
|
return None
|
|
373
466
|
if query.select_for_update:
|
|
467
|
+
self._query_signature_cache = None
|
|
374
468
|
return None
|
|
375
469
|
if query.combinator:
|
|
470
|
+
self._query_signature_cache = None
|
|
376
471
|
return None
|
|
377
472
|
if query.distinct:
|
|
473
|
+
self._query_signature_cache = None
|
|
378
474
|
return None
|
|
379
475
|
if getattr(self._data, "_prefetch_related_lookups", ()):
|
|
476
|
+
self._query_signature_cache = None
|
|
380
477
|
return None
|
|
381
478
|
deferred_loading = getattr(query, "deferred_loading", None)
|
|
382
479
|
if isinstance(deferred_loading, tuple) and deferred_loading[0]:
|
|
480
|
+
self._query_signature_cache = None
|
|
383
481
|
return None
|
|
384
482
|
try:
|
|
385
483
|
sql, params = self._data.query.sql_with_params()
|
|
386
484
|
except (EmptyResultSet, FieldError, TypeError, ValueError):
|
|
485
|
+
self._query_signature_cache = None
|
|
387
486
|
return None
|
|
388
|
-
|
|
487
|
+
signature = (
|
|
389
488
|
self._manager_class,
|
|
390
489
|
self._data.model,
|
|
391
490
|
self._data.db,
|
|
@@ -395,6 +494,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
395
494
|
self._sort_keys,
|
|
396
495
|
self._sort_reverse,
|
|
397
496
|
)
|
|
497
|
+
self._query_signature_cache = signature
|
|
498
|
+
return signature
|
|
398
499
|
|
|
399
500
|
def _bucket_index_source_signature(self) -> Hashable:
|
|
400
501
|
"""Return a queryset signature when safe, otherwise use object identity."""
|
|
@@ -501,6 +602,38 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
501
602
|
return None
|
|
502
603
|
return cast(tuple[models.Model, ...], cached)
|
|
503
604
|
|
|
605
|
+
def _can_cache_run_scoped_managers(self) -> bool:
|
|
606
|
+
if self._manager_class.__init__ is not GeneralManager.__init__:
|
|
607
|
+
return False
|
|
608
|
+
return callable(
|
|
609
|
+
getattr(self._manager_class.Interface, "_from_trusted_orm_instance", None)
|
|
610
|
+
)
|
|
611
|
+
|
|
612
|
+
def _get_run_scoped_managers(self) -> tuple[GeneralManagerType, ...] | None:
|
|
613
|
+
"""Load or reuse manager wrappers for a trusted row snapshot."""
|
|
614
|
+
if not self._can_cache_run_scoped_managers():
|
|
615
|
+
return None
|
|
616
|
+
context = current_calculation_run_context()
|
|
617
|
+
if context is None:
|
|
618
|
+
return None
|
|
619
|
+
signature = self._query_signature()
|
|
620
|
+
if signature is None:
|
|
621
|
+
return None
|
|
622
|
+
cached = context.get_orm_bucket_managers(signature)
|
|
623
|
+
if cached is not None:
|
|
624
|
+
managers = cast(tuple[GeneralManagerType, ...], cached)
|
|
625
|
+
for manager in managers:
|
|
626
|
+
self._manager_class._track_identification_dependency(
|
|
627
|
+
manager.identification
|
|
628
|
+
)
|
|
629
|
+
return managers
|
|
630
|
+
rows = self._get_run_scoped_rows()
|
|
631
|
+
if rows is None:
|
|
632
|
+
return None
|
|
633
|
+
managers = tuple(self._build_manager_from_instance(row) for row in rows)
|
|
634
|
+
context.set_orm_bucket_managers(signature, managers)
|
|
635
|
+
return managers
|
|
636
|
+
|
|
504
637
|
@staticmethod
|
|
505
638
|
def _snapshot_get_primary_key(
|
|
506
639
|
kwargs: Mapping[str, LookupValue],
|
|
@@ -528,21 +661,33 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
528
661
|
return kwargs["id"]
|
|
529
662
|
return None
|
|
530
663
|
|
|
664
|
+
def _can_materialize_count_snapshot(self) -> bool:
|
|
665
|
+
"""Return whether count/len may populate a bounded run-scoped snapshot."""
|
|
666
|
+
context = current_calculation_run_context()
|
|
667
|
+
if context is None:
|
|
668
|
+
return False
|
|
669
|
+
query = getattr(self._data, "query", None)
|
|
670
|
+
if not isinstance(query, Query):
|
|
671
|
+
return False
|
|
672
|
+
where = getattr(query, "where", None)
|
|
673
|
+
children = getattr(where, "children", None)
|
|
674
|
+
return bool(children)
|
|
675
|
+
|
|
531
676
|
def _track_effective_dependencies(self) -> None:
|
|
532
677
|
"""Record the bucket's effective filter/exclude state when it is evaluated."""
|
|
533
678
|
manager_name = self._manager_class.__name__
|
|
534
679
|
normalized_filters = self._normalize_dependency_mapping(self.filters)
|
|
535
680
|
normalized_excludes = self._normalize_dependency_mapping(self.excludes)
|
|
536
681
|
if self.filters:
|
|
537
|
-
DependencyTracker.
|
|
682
|
+
DependencyTracker._track_validated(
|
|
538
683
|
manager_name,
|
|
539
684
|
"filter",
|
|
540
685
|
serialize_dependency_identifier(normalized_filters),
|
|
541
686
|
)
|
|
542
687
|
else:
|
|
543
|
-
DependencyTracker.
|
|
688
|
+
DependencyTracker._track_validated(manager_name, "all", "")
|
|
544
689
|
if self.excludes:
|
|
545
|
-
DependencyTracker.
|
|
690
|
+
DependencyTracker._track_validated(
|
|
546
691
|
manager_name,
|
|
547
692
|
"exclude",
|
|
548
693
|
serialize_dependency_identifier(normalized_excludes),
|
|
@@ -554,7 +699,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
554
699
|
"excludes": normalized_excludes,
|
|
555
700
|
"reverse": self._sort_reverse,
|
|
556
701
|
}
|
|
557
|
-
DependencyTracker.
|
|
702
|
+
DependencyTracker._track_validated(
|
|
558
703
|
manager_name,
|
|
559
704
|
"filter",
|
|
560
705
|
serialize_dependency_identifier({f"__sort__{sort_key}": payload}),
|
|
@@ -576,6 +721,10 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
576
721
|
GeneralManagerType: Manager instance for each primary key in the queryset.
|
|
577
722
|
"""
|
|
578
723
|
self._track_effective_dependencies()
|
|
724
|
+
managers = self._get_run_scoped_managers()
|
|
725
|
+
if managers is not None:
|
|
726
|
+
yield from managers
|
|
727
|
+
return
|
|
579
728
|
rows = self._get_run_scoped_rows()
|
|
580
729
|
if rows is not None:
|
|
581
730
|
for row in rows:
|
|
@@ -782,7 +931,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
782
931
|
qs = qs.filter(pk__in=ids)
|
|
783
932
|
|
|
784
933
|
merged_filter = self.__merge_filter_definitions(self.filters, **kwargs)
|
|
785
|
-
|
|
934
|
+
bucket = self.__class__(
|
|
786
935
|
qs,
|
|
787
936
|
self._manager_class,
|
|
788
937
|
merged_filter,
|
|
@@ -792,6 +941,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
792
941
|
sort_reverse=self._sort_reverse,
|
|
793
942
|
run_scoped_cacheable=self._run_scoped_cacheable,
|
|
794
943
|
)
|
|
944
|
+
if not annotations and not python_filters:
|
|
945
|
+
bucket._set_trusted_query_signature(
|
|
946
|
+
self._trusted_query_signature_with("filter", orm_kwargs)
|
|
947
|
+
)
|
|
948
|
+
return bucket
|
|
795
949
|
|
|
796
950
|
def exclude(self, **kwargs: LookupValue) -> DatabaseBucket[GeneralManagerType]:
|
|
797
951
|
"""
|
|
@@ -843,7 +997,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
843
997
|
qs = qs.exclude(pk__in=ids)
|
|
844
998
|
|
|
845
999
|
merged_exclude = self.__merge_filter_definitions(self.excludes, **kwargs)
|
|
846
|
-
|
|
1000
|
+
bucket = self.__class__(
|
|
847
1001
|
qs,
|
|
848
1002
|
self._manager_class,
|
|
849
1003
|
self.filters,
|
|
@@ -853,6 +1007,11 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
853
1007
|
sort_reverse=self._sort_reverse,
|
|
854
1008
|
run_scoped_cacheable=self._run_scoped_cacheable,
|
|
855
1009
|
)
|
|
1010
|
+
if not annotations and not python_filters:
|
|
1011
|
+
bucket._set_trusted_query_signature(
|
|
1012
|
+
self._trusted_query_signature_with("exclude", orm_kwargs)
|
|
1013
|
+
)
|
|
1014
|
+
return bucket
|
|
856
1015
|
|
|
857
1016
|
def first(self) -> GeneralManagerType | None:
|
|
858
1017
|
"""
|
|
@@ -875,7 +1034,23 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
875
1034
|
if not primary_keys:
|
|
876
1035
|
return None
|
|
877
1036
|
return self._build_manager_from_primary_key(primary_keys[0])
|
|
1037
|
+
context = current_calculation_run_context()
|
|
1038
|
+
signature = self._query_signature() if context is not None else None
|
|
1039
|
+
if context is not None and signature is not None:
|
|
1040
|
+
cached = context.get_orm_bucket_first_row(
|
|
1041
|
+
signature,
|
|
1042
|
+
_FIRST_ROW_CACHE_MISS,
|
|
1043
|
+
)
|
|
1044
|
+
if cached is _FIRST_ROW_CACHE_NONE:
|
|
1045
|
+
return None
|
|
1046
|
+
if cached is not _FIRST_ROW_CACHE_MISS:
|
|
1047
|
+
return self._build_manager_from_instance(cast(models.Model, cached))
|
|
878
1048
|
first_element = self._data.first()
|
|
1049
|
+
if context is not None and signature is not None:
|
|
1050
|
+
context.set_orm_bucket_first_row(
|
|
1051
|
+
signature,
|
|
1052
|
+
_FIRST_ROW_CACHE_NONE if first_element is None else first_element,
|
|
1053
|
+
)
|
|
879
1054
|
if first_element is None:
|
|
880
1055
|
return None
|
|
881
1056
|
return self._build_manager_from_instance(first_element)
|
|
@@ -917,6 +1092,10 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
917
1092
|
int: Number of represented rows.
|
|
918
1093
|
"""
|
|
919
1094
|
self._track_effective_dependencies()
|
|
1095
|
+
if self._can_materialize_count_snapshot():
|
|
1096
|
+
rows = self._get_run_scoped_rows()
|
|
1097
|
+
if rows is not None:
|
|
1098
|
+
return len(rows)
|
|
920
1099
|
primary_keys = self._peek_run_scoped_primary_keys()
|
|
921
1100
|
if primary_keys is not None:
|
|
922
1101
|
return len(primary_keys)
|
|
@@ -932,7 +1111,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
932
1111
|
Returns:
|
|
933
1112
|
DatabaseBucket[GeneralManagerType]: Bucket encapsulating `self._data.all()`.
|
|
934
1113
|
"""
|
|
935
|
-
|
|
1114
|
+
bucket = self.__class__(
|
|
936
1115
|
self._data.all(),
|
|
937
1116
|
self._manager_class,
|
|
938
1117
|
self.filters,
|
|
@@ -942,6 +1121,8 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
942
1121
|
sort_reverse=self._sort_reverse,
|
|
943
1122
|
run_scoped_cacheable=self._run_scoped_cacheable,
|
|
944
1123
|
)
|
|
1124
|
+
bucket._set_trusted_query_signature(self._trusted_query_signature)
|
|
1125
|
+
return bucket
|
|
945
1126
|
|
|
946
1127
|
def get(self, **kwargs: LookupValue) -> GeneralManagerType:
|
|
947
1128
|
"""
|
|
@@ -1027,21 +1208,43 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
1027
1208
|
return self._build_manager_from_primary_key(primary_keys[item])
|
|
1028
1209
|
return self._build_manager_from_instance(self._data[item])
|
|
1029
1210
|
|
|
1211
|
+
def __bool__(self) -> bool:
|
|
1212
|
+
"""
|
|
1213
|
+
Return whether the bucket contains at least one row without counting all rows.
|
|
1214
|
+
|
|
1215
|
+
Truthiness is an existence check, not a cardinality request. Reuse any
|
|
1216
|
+
active run-context snapshot first, then cache a queryset ``exists()``
|
|
1217
|
+
result for equivalent trusted querysets in the same calculation run.
|
|
1218
|
+
"""
|
|
1219
|
+
self._track_effective_dependencies()
|
|
1220
|
+
rows = self._peek_run_scoped_rows()
|
|
1221
|
+
if rows is not None:
|
|
1222
|
+
return bool(rows)
|
|
1223
|
+
primary_keys = self._peek_run_scoped_primary_keys()
|
|
1224
|
+
if primary_keys is not None:
|
|
1225
|
+
return bool(primary_keys)
|
|
1226
|
+
context = current_calculation_run_context()
|
|
1227
|
+
signature = self._query_signature() if context is not None else None
|
|
1228
|
+
if context is not None and signature is not None:
|
|
1229
|
+
cached = context.get_orm_bucket_exists(signature)
|
|
1230
|
+
if cached is not None:
|
|
1231
|
+
return bool(cached)
|
|
1232
|
+
exists = bool(self._data.exists())
|
|
1233
|
+
if context is not None and signature is not None:
|
|
1234
|
+
context.set_orm_bucket_exists(signature, exists)
|
|
1235
|
+
return exists
|
|
1236
|
+
|
|
1030
1237
|
def __len__(self) -> int:
|
|
1031
1238
|
"""
|
|
1032
1239
|
Return the number of rows represented by the bucket.
|
|
1033
1240
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1241
|
+
Delegates to `count()` so dependency tracking, run-scoped snapshots, and
|
|
1242
|
+
queryset fallback behavior stay aligned between both cardinality paths.
|
|
1036
1243
|
|
|
1037
1244
|
Returns:
|
|
1038
1245
|
int: Number of represented rows.
|
|
1039
1246
|
"""
|
|
1040
|
-
self.
|
|
1041
|
-
primary_keys = self._peek_run_scoped_primary_keys()
|
|
1042
|
-
if primary_keys is not None:
|
|
1043
|
-
return len(primary_keys)
|
|
1044
|
-
return int(self._data.count())
|
|
1247
|
+
return self.count()
|
|
1045
1248
|
|
|
1046
1249
|
def __str__(self) -> str:
|
|
1047
1250
|
"""
|
|
@@ -1169,7 +1372,7 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
1169
1372
|
except (FieldError, TypeError, ValueError) as error:
|
|
1170
1373
|
raise QuerysetOrderingError(error) from error
|
|
1171
1374
|
|
|
1172
|
-
|
|
1375
|
+
bucket = self.__class__(
|
|
1173
1376
|
qs,
|
|
1174
1377
|
self._manager_class,
|
|
1175
1378
|
self.filters,
|
|
@@ -1179,6 +1382,9 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
1179
1382
|
sort_reverse=reverse,
|
|
1180
1383
|
run_scoped_cacheable=self._run_scoped_cacheable,
|
|
1181
1384
|
)
|
|
1385
|
+
if not annotations and not python_keys:
|
|
1386
|
+
bucket._set_trusted_query_signature(self._trusted_query_signature)
|
|
1387
|
+
return bucket
|
|
1182
1388
|
|
|
1183
1389
|
def none(self) -> DatabaseBucket[GeneralManagerType]:
|
|
1184
1390
|
"""
|
|
@@ -1193,4 +1399,6 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
1193
1399
|
"""
|
|
1194
1400
|
own = self.all()
|
|
1195
1401
|
own._data = own._data.none()
|
|
1402
|
+
own._query_signature_cache = _QUERY_SIGNATURE_NOT_COMPUTED
|
|
1403
|
+
own._trusted_query_signature = None
|
|
1196
1404
|
return own
|
|
@@ -135,12 +135,20 @@ class DependencyTracker:
|
|
|
135
135
|
raise _InvalidDependencyTrackerValueError
|
|
136
136
|
if operation not in _SUPPORTED_OPERATIONS:
|
|
137
137
|
raise _InvalidDependencyTrackerOperationError(operation)
|
|
138
|
+
DependencyTracker._track_validated(class_name, operation, identifier)
|
|
139
|
+
|
|
140
|
+
@staticmethod
|
|
141
|
+
def _track_validated(
|
|
142
|
+
class_name: general_manager_name,
|
|
143
|
+
operation: filter_type,
|
|
144
|
+
identifier: str,
|
|
145
|
+
) -> None:
|
|
146
|
+
"""Record an already-validated dependency tuple in active collectors."""
|
|
138
147
|
if _dependency_storage.depth < 0:
|
|
139
148
|
return
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
dep_set.add((class_name, operation, identifier))
|
|
149
|
+
dependency = (class_name, operation, identifier)
|
|
150
|
+
for dep_set in _dependency_storage.dependencies:
|
|
151
|
+
dep_set.add(dependency)
|
|
144
152
|
|
|
145
153
|
@staticmethod
|
|
146
154
|
def is_active() -> bool:
|
{generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_cache.py
RENAMED
|
@@ -9,7 +9,8 @@ from typing import Protocol, TypeGuard, cast
|
|
|
9
9
|
from general_manager.cache.cache_tracker import DependencyTracker
|
|
10
10
|
from general_manager.cache.dependency_index import Dependency
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
LEGACY_DEPENDENCY_CACHE_ENTRY_VERSION = 1
|
|
13
|
+
DEPENDENCY_CACHE_ENTRY_VERSION = 2
|
|
13
14
|
_VALID_DEPENDENCY_ACTIONS = frozenset(
|
|
14
15
|
{"filter", "exclude", "identification", "request_query", "all"}
|
|
15
16
|
)
|
|
@@ -258,10 +259,19 @@ def _combined_payload_to_hit(
|
|
|
258
259
|
) -> DependencyCacheHit | None | _MissingSentinel:
|
|
259
260
|
if not isinstance(payload, DependencyCacheEntry):
|
|
260
261
|
return None
|
|
261
|
-
if payload.version
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
262
|
+
if payload.version == LEGACY_DEPENDENCY_CACHE_ENTRY_VERSION:
|
|
263
|
+
dependencies = _legacy_dependency_set(payload.dependencies)
|
|
264
|
+
if dependencies is None:
|
|
265
|
+
return _MISSING
|
|
266
|
+
elif payload.version == DEPENDENCY_CACHE_ENTRY_VERSION:
|
|
267
|
+
# Legacy entries may contain arbitrary tuple-like data, so the
|
|
268
|
+
# _legacy_dependency_set path validates each dependency. Current entries
|
|
269
|
+
# come from make_dependency_cache_entry after that same validation flow,
|
|
270
|
+
# so keep deserialization on the frozenset type-check fast path.
|
|
271
|
+
if not isinstance(payload.dependencies, frozenset):
|
|
272
|
+
return _MISSING
|
|
273
|
+
dependencies = payload.dependencies
|
|
274
|
+
else:
|
|
265
275
|
return _MISSING
|
|
266
276
|
return DependencyCacheHit(
|
|
267
277
|
value=payload.value,
|
{generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_matching.py
RENAMED
|
@@ -8,6 +8,7 @@ import re
|
|
|
8
8
|
from collections.abc import Callable, Mapping, Sequence, Set as AbstractSet
|
|
9
9
|
from dataclasses import dataclass
|
|
10
10
|
from datetime import date, datetime
|
|
11
|
+
from json.encoder import encode_basestring_ascii
|
|
11
12
|
from typing import Literal, Protocol, cast
|
|
12
13
|
|
|
13
14
|
LookupOperator = Literal[
|
|
@@ -29,6 +30,8 @@ SCAN_OPERATORS = frozenset(
|
|
|
29
30
|
)
|
|
30
31
|
SUPPORTED_LOOKUP_OPERATORS = EXACT_OPERATORS | SCAN_OPERATORS
|
|
31
32
|
UNDEFINED = object()
|
|
33
|
+
_SCALAR_NORMALIZATION_MISS = object()
|
|
34
|
+
_SCALAR_SERIALIZATION_MISS = object()
|
|
32
35
|
|
|
33
36
|
|
|
34
37
|
type NormalizedDependencyValue = (
|
|
@@ -62,6 +65,47 @@ class SupportsDependencyComparison(Protocol):
|
|
|
62
65
|
...
|
|
63
66
|
|
|
64
67
|
|
|
68
|
+
def _normalize_scalar_dependency_value(value: object) -> object:
|
|
69
|
+
"""
|
|
70
|
+
Return the scalar-only equivalent of `normalize_dependency_value`.
|
|
71
|
+
|
|
72
|
+
This avoids the slower general path for simple scalars only, and its output
|
|
73
|
+
must remain equivalent to full normalization for every value it accepts.
|
|
74
|
+
"""
|
|
75
|
+
|
|
76
|
+
if isinstance(value, datetime):
|
|
77
|
+
return value.isoformat()
|
|
78
|
+
if isinstance(value, date):
|
|
79
|
+
return value.isoformat()
|
|
80
|
+
if isinstance(value, (str, int, float, bool)) or value is None:
|
|
81
|
+
return value
|
|
82
|
+
return _SCALAR_NORMALIZATION_MISS
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _serialize_scalar_dependency_value(value: object) -> str | object:
|
|
86
|
+
"""
|
|
87
|
+
Serialize simple scalars without the slower generic JSON path.
|
|
88
|
+
|
|
89
|
+
Outputs must remain equivalent to full normalization followed by
|
|
90
|
+
`json.dumps(..., sort_keys=True)`. Floats are intentionally excluded so the
|
|
91
|
+
caller can preserve Python's JSON spelling for finite and non-finite values.
|
|
92
|
+
"""
|
|
93
|
+
|
|
94
|
+
if isinstance(value, str):
|
|
95
|
+
return encode_basestring_ascii(value)
|
|
96
|
+
if value is None:
|
|
97
|
+
return "null"
|
|
98
|
+
if value is True:
|
|
99
|
+
return "true"
|
|
100
|
+
if value is False:
|
|
101
|
+
return "false"
|
|
102
|
+
if type(value) is int:
|
|
103
|
+
return str(value)
|
|
104
|
+
if isinstance(value, date):
|
|
105
|
+
return encode_basestring_ascii(value.isoformat())
|
|
106
|
+
return _SCALAR_SERIALIZATION_MISS
|
|
107
|
+
|
|
108
|
+
|
|
65
109
|
@dataclass(frozen=True, slots=True)
|
|
66
110
|
class LookupSpec:
|
|
67
111
|
"""Parsed dependency lookup path and operator."""
|
|
@@ -75,6 +119,11 @@ def normalize_dependency_value(value: object) -> NormalizedDependencyValue:
|
|
|
75
119
|
"""Return a deterministic JSON-compatible representation for dependency data."""
|
|
76
120
|
if isinstance(value, Mapping):
|
|
77
121
|
mapping = cast(Mapping[object, object], value)
|
|
122
|
+
if len(mapping) == 1:
|
|
123
|
+
key, val = next(iter(mapping.items()))
|
|
124
|
+
normalized_value = _normalize_scalar_dependency_value(val)
|
|
125
|
+
if normalized_value is not _SCALAR_NORMALIZATION_MISS:
|
|
126
|
+
return {str(key): cast(NormalizedDependencyValue, normalized_value)}
|
|
78
127
|
return {
|
|
79
128
|
str(key): normalize_dependency_value(val)
|
|
80
129
|
for key, val in sorted(mapping.items(), key=lambda item: str(item[0]))
|
|
@@ -101,12 +150,24 @@ def normalize_dependency_value(value: object) -> NormalizedDependencyValue:
|
|
|
101
150
|
|
|
102
151
|
def serialize_normalized_value(value: object) -> str:
|
|
103
152
|
"""Serialize dependency values in the canonical dependency format."""
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
153
|
+
serialized_scalar = _serialize_scalar_dependency_value(value)
|
|
154
|
+
if serialized_scalar is not _SCALAR_SERIALIZATION_MISS:
|
|
155
|
+
return cast(str, serialized_scalar)
|
|
156
|
+
if isinstance(value, float):
|
|
107
157
|
return json.dumps(value)
|
|
108
|
-
if isinstance(value,
|
|
109
|
-
|
|
158
|
+
if isinstance(value, Mapping):
|
|
159
|
+
mapping = cast(Mapping[object, object], value)
|
|
160
|
+
if len(mapping) == 1:
|
|
161
|
+
key, val = next(iter(mapping.items()))
|
|
162
|
+
normalized_value = _normalize_scalar_dependency_value(val)
|
|
163
|
+
serialized_value = _serialize_scalar_dependency_value(normalized_value)
|
|
164
|
+
if serialized_value is not _SCALAR_SERIALIZATION_MISS:
|
|
165
|
+
return (
|
|
166
|
+
"{"
|
|
167
|
+
f"{encode_basestring_ascii(str(key))}: "
|
|
168
|
+
f"{cast(str, serialized_value)}"
|
|
169
|
+
"}"
|
|
170
|
+
)
|
|
110
171
|
return json.dumps(normalize_dependency_value(value), sort_keys=True)
|
|
111
172
|
|
|
112
173
|
|
{generalmanager-0.60.0 → generalmanager-0.60.1}/src/general_manager/cache/dependency_shards.py
RENAMED
|
@@ -13,6 +13,7 @@ import hashlib
|
|
|
13
13
|
from collections.abc import Iterable, Mapping
|
|
14
14
|
from collections import defaultdict
|
|
15
15
|
from dataclasses import dataclass, field
|
|
16
|
+
from functools import lru_cache
|
|
16
17
|
from typing import Literal
|
|
17
18
|
|
|
18
19
|
from django.core.cache import cache
|
|
@@ -377,6 +378,7 @@ def clear_legacy_dependency_index() -> set[str]:
|
|
|
377
378
|
return cache_keys
|
|
378
379
|
|
|
379
380
|
|
|
381
|
+
@lru_cache(maxsize=16384)
|
|
380
382
|
def _shard_keys_for_dependency(
|
|
381
383
|
manager_name: str,
|
|
382
384
|
action: DependencyAction,
|