GeneralManager 0.60.1__tar.gz → 0.60.2__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.1/src/GeneralManager.egg-info → generalmanager-0.60.2}/PKG-INFO +1 -1
- {generalmanager-0.60.1 → generalmanager-0.60.2}/pyproject.toml +1 -1
- {generalmanager-0.60.1 → generalmanager-0.60.2/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/property.py +4 -1
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/database_bucket.py +48 -9
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/cache_decorator.py +188 -4
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/cache_tracker.py +62 -4
- generalmanager-0.60.2/src/general_manager/cache/dependency_cache.py +576 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/dependency_index.py +9 -9
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/dependency_matching.py +73 -11
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/dependency_publish.py +225 -13
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/dependency_shards.py +39 -38
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/run_context.py +54 -6
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/base_interface.py +209 -46
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/calculation/lifecycle.py +1 -7
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/core/utils.py +1 -14
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +30 -2
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/manager/general_manager.py +125 -46
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/manager/meta.py +83 -20
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/measurement/measurement.py +95 -33
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/json_encoder.py +3 -1
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/make_cache_key.py +57 -12
- generalmanager-0.60.1/src/general_manager/cache/dependency_cache.py +0 -297
- {generalmanager-0.60.1 → generalmanager-0.60.2}/LICENSE +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/README.md +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/setup.cfg +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_resolvers.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/remote_invalidation.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/apps.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/signals.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/conf.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/logging.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/py.typed +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/args_to_kwargs.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/none_to_zero.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/signal_bridge.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/tests/test_settings.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/tests/test_urls.py +0 -0
- {generalmanager-0.60.1 → generalmanager-0.60.2}/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.2
|
|
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.2"
|
|
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.2
|
|
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
|
|
@@ -142,7 +142,10 @@ class GraphQLProperty(property):
|
|
|
142
142
|
@wraps(fget)
|
|
143
143
|
def resolver(instance: object) -> object:
|
|
144
144
|
"""Resolve the property through the selected cached wrapper."""
|
|
145
|
-
|
|
145
|
+
cached_fget = self._cached_fget
|
|
146
|
+
if cached_fget is None:
|
|
147
|
+
cached_fget = self._get_cached_fget()
|
|
148
|
+
return cached_fget(instance)
|
|
146
149
|
|
|
147
150
|
super().__init__(resolver, doc=doc)
|
|
148
151
|
self.is_graphql_resolver = True
|
{generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/bucket/database_bucket.py
RENAMED
|
@@ -11,7 +11,10 @@ from django.db.models.sql.query import Query
|
|
|
11
11
|
|
|
12
12
|
from general_manager.bucket.base_bucket import Bucket
|
|
13
13
|
from general_manager.cache.cache_tracker import DependencyTracker
|
|
14
|
-
from general_manager.cache.dependency_index import
|
|
14
|
+
from general_manager.cache.dependency_index import (
|
|
15
|
+
Dependency,
|
|
16
|
+
serialize_dependency_identifier,
|
|
17
|
+
)
|
|
15
18
|
from general_manager.cache.run_context import current_calculation_run_context
|
|
16
19
|
from general_manager.manager.general_manager import GeneralManager
|
|
17
20
|
from general_manager.utils.filter_parser import create_filter_function
|
|
@@ -605,10 +608,29 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
605
608
|
def _can_cache_run_scoped_managers(self) -> bool:
|
|
606
609
|
if self._manager_class.__init__ is not GeneralManager.__init__:
|
|
607
610
|
return False
|
|
611
|
+
if not type.__getattribute__(
|
|
612
|
+
self._manager_class,
|
|
613
|
+
"_gm_uses_default_identification_dependency_active",
|
|
614
|
+
):
|
|
615
|
+
return False
|
|
608
616
|
return callable(
|
|
609
617
|
getattr(self._manager_class.Interface, "_from_trusted_orm_instance", None)
|
|
610
618
|
)
|
|
611
619
|
|
|
620
|
+
def _manager_identification_dependencies(
|
|
621
|
+
self,
|
|
622
|
+
managers: tuple[GeneralManagerType, ...],
|
|
623
|
+
) -> frozenset[Dependency]:
|
|
624
|
+
manager_name = type.__getattribute__(self._manager_class, "__name__")
|
|
625
|
+
return frozenset(
|
|
626
|
+
(
|
|
627
|
+
manager_name,
|
|
628
|
+
"identification",
|
|
629
|
+
serialize_dependency_identifier(manager.identification),
|
|
630
|
+
)
|
|
631
|
+
for manager in managers
|
|
632
|
+
)
|
|
633
|
+
|
|
612
634
|
def _get_run_scoped_managers(self) -> tuple[GeneralManagerType, ...] | None:
|
|
613
635
|
"""Load or reuse manager wrappers for a trusted row snapshot."""
|
|
614
636
|
if not self._can_cache_run_scoped_managers():
|
|
@@ -622,16 +644,24 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
622
644
|
cached = context.get_orm_bucket_managers(signature)
|
|
623
645
|
if cached is not None:
|
|
624
646
|
managers = cast(tuple[GeneralManagerType, ...], cached)
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
647
|
+
dependencies = context.get_orm_bucket_manager_dependencies(signature)
|
|
648
|
+
if dependencies is not None:
|
|
649
|
+
DependencyTracker._track_many_validated(dependencies)
|
|
650
|
+
else:
|
|
651
|
+
for manager in managers:
|
|
652
|
+
self._manager_class._track_identification_dependency(
|
|
653
|
+
manager.identification
|
|
654
|
+
)
|
|
629
655
|
return managers
|
|
630
656
|
rows = self._get_run_scoped_rows()
|
|
631
657
|
if rows is None:
|
|
632
658
|
return None
|
|
633
659
|
managers = tuple(self._build_manager_from_instance(row) for row in rows)
|
|
634
|
-
context.set_orm_bucket_managers(
|
|
660
|
+
context.set_orm_bucket_managers(
|
|
661
|
+
signature,
|
|
662
|
+
managers,
|
|
663
|
+
self._manager_identification_dependencies(managers),
|
|
664
|
+
)
|
|
635
665
|
return managers
|
|
636
666
|
|
|
637
667
|
@staticmethod
|
|
@@ -675,9 +705,18 @@ class DatabaseBucket(Bucket[GeneralManagerType]):
|
|
|
675
705
|
|
|
676
706
|
def _track_effective_dependencies(self) -> None:
|
|
677
707
|
"""Record the bucket's effective filter/exclude state when it is evaluated."""
|
|
678
|
-
manager_name = self._manager_class
|
|
679
|
-
|
|
680
|
-
|
|
708
|
+
manager_name = type.__getattribute__(self._manager_class, "__name__")
|
|
709
|
+
needs_sort_payload = bool(self._sort_keys)
|
|
710
|
+
normalized_filters = (
|
|
711
|
+
self._normalize_dependency_mapping(self.filters)
|
|
712
|
+
if self.filters or needs_sort_payload
|
|
713
|
+
else {}
|
|
714
|
+
)
|
|
715
|
+
normalized_excludes = (
|
|
716
|
+
self._normalize_dependency_mapping(self.excludes)
|
|
717
|
+
if self.excludes or needs_sort_payload
|
|
718
|
+
else {}
|
|
719
|
+
)
|
|
681
720
|
if self.filters:
|
|
682
721
|
DependencyTracker._track_validated(
|
|
683
722
|
manager_name,
|
{generalmanager-0.60.1 → generalmanager-0.60.2}/src/general_manager/cache/cache_decorator.py
RENAMED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable, Iterable
|
|
4
4
|
from functools import wraps
|
|
5
|
+
from hashlib import sha256
|
|
5
6
|
from typing import (
|
|
6
7
|
Literal,
|
|
7
8
|
Protocol,
|
|
@@ -15,6 +16,16 @@ from django.core.cache import cache as django_cache
|
|
|
15
16
|
from general_manager.cache.cache_tracker import DependencyTracker
|
|
16
17
|
from general_manager.cache.dependency_cache import (
|
|
17
18
|
DependencyCacheHit,
|
|
19
|
+
dependency_cache_prefetch_bundle_key,
|
|
20
|
+
dependency_cache_prefetch_segment_bundle_key,
|
|
21
|
+
dependency_cache_prefetch_segment_index_key,
|
|
22
|
+
dependency_cache_prefetch_segment_value_bundle_key,
|
|
23
|
+
dependency_cache_prefetch_value_bundle_key,
|
|
24
|
+
read_many_dependency_cache_hits,
|
|
25
|
+
read_many_dependency_cache_prefetch_bundle_hits,
|
|
26
|
+
read_many_dependency_cache_prefetch_bundle_values,
|
|
27
|
+
read_dependency_cache_prefetch_bundle_hits,
|
|
28
|
+
read_dependency_cache_prefetch_bundle_values,
|
|
18
29
|
read_dependency_cache_hit,
|
|
19
30
|
replay_dependency_cache_hit,
|
|
20
31
|
)
|
|
@@ -63,6 +74,10 @@ FuncT = TypeVar("FuncT", bound=Callable[..., object])
|
|
|
63
74
|
CacheScope = Literal["dependency", "run", "timeout", "none"]
|
|
64
75
|
|
|
65
76
|
_SENTINEL = object()
|
|
77
|
+
_RUN_CACHE_MISS = object()
|
|
78
|
+
_DEPENDENCY_CACHE_PREFETCH_MANIFEST_PREFIX = "dependency_cache_prefetch_manifest"
|
|
79
|
+
_DEPENDENCY_CACHE_PREFETCH_ATTEMPT_PREFIX = "dependency_cache_prefetch_attempt"
|
|
80
|
+
_DEPENDENCY_CACHE_PREFETCH_VALUE_PREFIX = "dependency_cache_prefetch_value"
|
|
66
81
|
logger = get_logger("cache.decorator")
|
|
67
82
|
|
|
68
83
|
|
|
@@ -169,7 +184,130 @@ def cached(
|
|
|
169
184
|
if timeout is not None and cache != "timeout":
|
|
170
185
|
raise CacheTimeoutConfigurationError.unexpected_timeout()
|
|
171
186
|
|
|
187
|
+
def dependency_cache_prefetch_manifest_key(
|
|
188
|
+
decorated_func: Callable[..., object],
|
|
189
|
+
) -> str:
|
|
190
|
+
raw = f"{decorated_func.__module__}:{decorated_func.__qualname__}".encode()
|
|
191
|
+
digest = sha256(raw, usedforsecurity=False).hexdigest()
|
|
192
|
+
return f"{_DEPENDENCY_CACHE_PREFETCH_MANIFEST_PREFIX}:{digest}"
|
|
193
|
+
|
|
194
|
+
def prefetch_dependency_cache_manifest(
|
|
195
|
+
context: object,
|
|
196
|
+
manifest_key: str,
|
|
197
|
+
) -> None:
|
|
198
|
+
if not callable(getattr(cache_backend, "get_many", None)):
|
|
199
|
+
return
|
|
200
|
+
if not all(
|
|
201
|
+
hasattr(context, attr)
|
|
202
|
+
for attr in (
|
|
203
|
+
"get",
|
|
204
|
+
"set",
|
|
205
|
+
"set_dependency_cache_hits",
|
|
206
|
+
)
|
|
207
|
+
):
|
|
208
|
+
return
|
|
209
|
+
attempt_key = (
|
|
210
|
+
_DEPENDENCY_CACHE_PREFETCH_ATTEMPT_PREFIX,
|
|
211
|
+
id(cache_backend),
|
|
212
|
+
manifest_key,
|
|
213
|
+
)
|
|
214
|
+
if context.get(attempt_key, False): # type: ignore[attr-defined]
|
|
215
|
+
return
|
|
216
|
+
context.set(attempt_key, True) # type: ignore[attr-defined]
|
|
217
|
+
|
|
218
|
+
segment_tokens = cache_backend.get(
|
|
219
|
+
dependency_cache_prefetch_segment_index_key(manifest_key),
|
|
220
|
+
(),
|
|
221
|
+
)
|
|
222
|
+
if isinstance(segment_tokens, (tuple, list, frozenset, set)):
|
|
223
|
+
valid_segment_tokens = tuple(
|
|
224
|
+
token for token in segment_tokens if isinstance(token, str)
|
|
225
|
+
)
|
|
226
|
+
else:
|
|
227
|
+
valid_segment_tokens = ()
|
|
228
|
+
|
|
229
|
+
if not DependencyTracker.is_active():
|
|
230
|
+
if valid_segment_tokens:
|
|
231
|
+
segment_value_keys = tuple(
|
|
232
|
+
dependency_cache_prefetch_segment_value_bundle_key(
|
|
233
|
+
manifest_key,
|
|
234
|
+
segment_token,
|
|
235
|
+
)
|
|
236
|
+
for segment_token in valid_segment_tokens
|
|
237
|
+
)
|
|
238
|
+
segment_values = read_many_dependency_cache_prefetch_bundle_values(
|
|
239
|
+
cache_backend,
|
|
240
|
+
segment_value_keys,
|
|
241
|
+
)
|
|
242
|
+
if segment_values:
|
|
243
|
+
for cache_key, value in segment_values.items():
|
|
244
|
+
context.set( # type: ignore[attr-defined]
|
|
245
|
+
(
|
|
246
|
+
_DEPENDENCY_CACHE_PREFETCH_VALUE_PREFIX,
|
|
247
|
+
id(cache_backend),
|
|
248
|
+
cache_key,
|
|
249
|
+
),
|
|
250
|
+
value,
|
|
251
|
+
)
|
|
252
|
+
return
|
|
253
|
+
|
|
254
|
+
bundle_values = read_dependency_cache_prefetch_bundle_values(
|
|
255
|
+
cache_backend,
|
|
256
|
+
dependency_cache_prefetch_value_bundle_key(manifest_key),
|
|
257
|
+
)
|
|
258
|
+
if bundle_values:
|
|
259
|
+
for cache_key, value in bundle_values.items():
|
|
260
|
+
context.set( # type: ignore[attr-defined]
|
|
261
|
+
(
|
|
262
|
+
_DEPENDENCY_CACHE_PREFETCH_VALUE_PREFIX,
|
|
263
|
+
id(cache_backend),
|
|
264
|
+
cache_key,
|
|
265
|
+
),
|
|
266
|
+
value,
|
|
267
|
+
)
|
|
268
|
+
return
|
|
269
|
+
|
|
270
|
+
if valid_segment_tokens:
|
|
271
|
+
segment_bundle_keys = tuple(
|
|
272
|
+
dependency_cache_prefetch_segment_bundle_key(
|
|
273
|
+
manifest_key,
|
|
274
|
+
segment_token,
|
|
275
|
+
)
|
|
276
|
+
for segment_token in valid_segment_tokens
|
|
277
|
+
)
|
|
278
|
+
segment_hits = read_many_dependency_cache_prefetch_bundle_hits(
|
|
279
|
+
cache_backend,
|
|
280
|
+
segment_bundle_keys,
|
|
281
|
+
)
|
|
282
|
+
if segment_hits:
|
|
283
|
+
context.set_dependency_cache_hits(segment_hits) # type: ignore[attr-defined]
|
|
284
|
+
return
|
|
285
|
+
|
|
286
|
+
bundle_hits = read_dependency_cache_prefetch_bundle_hits(
|
|
287
|
+
cache_backend,
|
|
288
|
+
dependency_cache_prefetch_bundle_key(manifest_key),
|
|
289
|
+
)
|
|
290
|
+
if bundle_hits:
|
|
291
|
+
context.set_dependency_cache_hits(bundle_hits) # type: ignore[attr-defined]
|
|
292
|
+
return
|
|
293
|
+
|
|
294
|
+
manifest = cache_backend.get(manifest_key, ())
|
|
295
|
+
if not isinstance(manifest, (tuple, list, frozenset, set)):
|
|
296
|
+
return
|
|
297
|
+
cache_keys = tuple(key for key in manifest if isinstance(key, str))
|
|
298
|
+
if not cache_keys:
|
|
299
|
+
return
|
|
300
|
+
hits = read_many_dependency_cache_hits(cache_backend, cache_keys)
|
|
301
|
+
if hits:
|
|
302
|
+
context.set_dependency_cache_hits(hits) # type: ignore[attr-defined]
|
|
303
|
+
|
|
172
304
|
def decorator(decorated_func: FuncT) -> FuncT:
|
|
305
|
+
prefetch_manifest_key = (
|
|
306
|
+
dependency_cache_prefetch_manifest_key(decorated_func)
|
|
307
|
+
if cache == "dependency"
|
|
308
|
+
else None
|
|
309
|
+
)
|
|
310
|
+
|
|
173
311
|
@wraps(decorated_func)
|
|
174
312
|
def wrapper(*args: object, **kwargs: object) -> object:
|
|
175
313
|
if cache == "none":
|
|
@@ -177,11 +315,21 @@ def cached(
|
|
|
177
315
|
|
|
178
316
|
if cache == "run":
|
|
179
317
|
key = make_cache_key(decorated_func, args, kwargs)
|
|
318
|
+
active_context = current_calculation_run_context()
|
|
319
|
+
if active_context is not None:
|
|
320
|
+
cached_run_value = active_context.get(key, _RUN_CACHE_MISS)
|
|
321
|
+
if cached_run_value is not _RUN_CACHE_MISS:
|
|
322
|
+
return cached_run_value
|
|
323
|
+
result = decorated_func(*args, **kwargs)
|
|
324
|
+
active_context.set(key, result)
|
|
325
|
+
return result
|
|
180
326
|
with ensure_calculation_run_context() as context:
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
)
|
|
327
|
+
cached_run_value = context.get(key, _RUN_CACHE_MISS)
|
|
328
|
+
if cached_run_value is not _RUN_CACHE_MISS:
|
|
329
|
+
return cached_run_value
|
|
330
|
+
result = decorated_func(*args, **kwargs)
|
|
331
|
+
context.set(key, result)
|
|
332
|
+
return result
|
|
185
333
|
|
|
186
334
|
key = make_cache_key(decorated_func, args, kwargs)
|
|
187
335
|
|
|
@@ -223,8 +371,23 @@ def cached(
|
|
|
223
371
|
)
|
|
224
372
|
return hit.value
|
|
225
373
|
|
|
374
|
+
def prefetched_value_from_context(context: object) -> object:
|
|
375
|
+
if DependencyTracker.is_active():
|
|
376
|
+
return _SENTINEL
|
|
377
|
+
return context.get( # type: ignore[attr-defined]
|
|
378
|
+
(
|
|
379
|
+
_DEPENDENCY_CACHE_PREFETCH_VALUE_PREFIX,
|
|
380
|
+
id(cache_backend),
|
|
381
|
+
key,
|
|
382
|
+
),
|
|
383
|
+
_SENTINEL,
|
|
384
|
+
)
|
|
385
|
+
|
|
226
386
|
prefetch_context = current_calculation_run_context()
|
|
227
387
|
if prefetch_context is not None:
|
|
388
|
+
prefetched_value = prefetched_value_from_context(prefetch_context)
|
|
389
|
+
if prefetched_value is not _SENTINEL:
|
|
390
|
+
return prefetched_value
|
|
228
391
|
prefetched_hit = prefetch_context.get_dependency_cache_hit(
|
|
229
392
|
key, _SENTINEL
|
|
230
393
|
)
|
|
@@ -233,6 +396,22 @@ def cached(
|
|
|
233
396
|
prefetched_hit,
|
|
234
397
|
"cache hit from dependency prefetch",
|
|
235
398
|
)
|
|
399
|
+
if prefetch_manifest_key is not None:
|
|
400
|
+
prefetch_dependency_cache_manifest(
|
|
401
|
+
prefetch_context,
|
|
402
|
+
prefetch_manifest_key,
|
|
403
|
+
)
|
|
404
|
+
prefetched_value = prefetched_value_from_context(prefetch_context)
|
|
405
|
+
if prefetched_value is not _SENTINEL:
|
|
406
|
+
return prefetched_value
|
|
407
|
+
prefetched_hit = prefetch_context.get_dependency_cache_hit(
|
|
408
|
+
key, _SENTINEL
|
|
409
|
+
)
|
|
410
|
+
if isinstance(prefetched_hit, DependencyCacheHit):
|
|
411
|
+
return return_cached_hit(
|
|
412
|
+
prefetched_hit,
|
|
413
|
+
"cache hit from dependency prefetch manifest",
|
|
414
|
+
)
|
|
236
415
|
|
|
237
416
|
cached_hit = read_dependency_cache_hit(
|
|
238
417
|
cache_backend,
|
|
@@ -288,6 +467,10 @@ def cached(
|
|
|
288
467
|
timeout=timeout,
|
|
289
468
|
started_generation=started_generation,
|
|
290
469
|
lease=lease,
|
|
470
|
+
dependencies_trusted=DependencyTracker._dependencies_are_tracker_captured(
|
|
471
|
+
dependencies
|
|
472
|
+
),
|
|
473
|
+
prefetch_manifest_key=prefetch_manifest_key,
|
|
291
474
|
)
|
|
292
475
|
)
|
|
293
476
|
lease_transferred_to_context = True
|
|
@@ -305,6 +488,7 @@ def cached(
|
|
|
305
488
|
if record_fn is record_dependencies
|
|
306
489
|
else record_many
|
|
307
490
|
),
|
|
491
|
+
prefetch_manifest_key=prefetch_manifest_key,
|
|
308
492
|
)
|
|
309
493
|
except CachePublishAborted:
|
|
310
494
|
logger.debug(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"""Context manager utilities for tracking cache dependencies per thread."""
|
|
2
2
|
|
|
3
|
+
from collections.abc import Collection, Iterable
|
|
3
4
|
import threading
|
|
4
5
|
from types import TracebackType
|
|
5
6
|
|
|
@@ -30,18 +31,32 @@ class _InvalidDependencyTrackerOperationError(ValueError):
|
|
|
30
31
|
super().__init__(f"Unsupported dependency tracker operation: {operation!r}")
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
class _TrackedDependencySet(set[Dependency]):
|
|
35
|
+
"""Dependency set returned by DependencyTracker for framework-captured deps."""
|
|
36
|
+
|
|
37
|
+
|
|
33
38
|
class _DependencyStorage(threading.local):
|
|
34
39
|
"""Thread-local dependency tracking stack."""
|
|
35
40
|
|
|
36
41
|
def __init__(self) -> None:
|
|
37
42
|
"""Initialize an inactive dependency stack for one thread."""
|
|
38
|
-
self.dependencies: list[
|
|
43
|
+
self.dependencies: list[_TrackedDependencySet] = []
|
|
39
44
|
self.depth = -1
|
|
45
|
+
self.stack_version = 0
|
|
46
|
+
self.last_dependency: Dependency | None = None
|
|
47
|
+
self.last_dependency_stack_version = -1
|
|
48
|
+
self.seen_dependencies: set[Dependency] = set()
|
|
49
|
+
self.seen_dependencies_stack_version = -1
|
|
40
50
|
|
|
41
51
|
def reset(self) -> None:
|
|
42
52
|
"""Clear all active dependency scopes for the current thread."""
|
|
43
53
|
self.dependencies.clear()
|
|
44
54
|
self.depth = -1
|
|
55
|
+
self.stack_version += 1
|
|
56
|
+
self.last_dependency = None
|
|
57
|
+
self.last_dependency_stack_version = -1
|
|
58
|
+
self.seen_dependencies.clear()
|
|
59
|
+
self.seen_dependencies_stack_version = -1
|
|
45
60
|
|
|
46
61
|
|
|
47
62
|
_dependency_storage = _DependencyStorage()
|
|
@@ -69,7 +84,8 @@ class DependencyTracker:
|
|
|
69
84
|
thread-local storage does not mutate sets that were already returned.
|
|
70
85
|
"""
|
|
71
86
|
_dependency_storage.depth += 1
|
|
72
|
-
_dependency_storage.dependencies.append(
|
|
87
|
+
_dependency_storage.dependencies.append(_TrackedDependencySet())
|
|
88
|
+
_dependency_storage.stack_version += 1
|
|
73
89
|
return _dependency_storage.dependencies[_dependency_storage.depth]
|
|
74
90
|
|
|
75
91
|
def __exit__(
|
|
@@ -98,6 +114,9 @@ class DependencyTracker:
|
|
|
98
114
|
return
|
|
99
115
|
_dependency_storage.dependencies.pop()
|
|
100
116
|
_dependency_storage.depth -= 1
|
|
117
|
+
_dependency_storage.stack_version += 1
|
|
118
|
+
_dependency_storage.last_dependency = None
|
|
119
|
+
_dependency_storage.last_dependency_stack_version = -1
|
|
101
120
|
|
|
102
121
|
@staticmethod
|
|
103
122
|
def track(
|
|
@@ -144,11 +163,50 @@ class DependencyTracker:
|
|
|
144
163
|
identifier: str,
|
|
145
164
|
) -> None:
|
|
146
165
|
"""Record an already-validated dependency tuple in active collectors."""
|
|
147
|
-
|
|
166
|
+
storage = _dependency_storage
|
|
167
|
+
if storage.depth < 0:
|
|
148
168
|
return
|
|
169
|
+
if storage.last_dependency_stack_version == storage.stack_version:
|
|
170
|
+
last_dependency = storage.last_dependency
|
|
171
|
+
if (
|
|
172
|
+
last_dependency is not None
|
|
173
|
+
and last_dependency[0] == class_name
|
|
174
|
+
and last_dependency[1] == operation
|
|
175
|
+
and last_dependency[2] == identifier
|
|
176
|
+
):
|
|
177
|
+
return
|
|
149
178
|
dependency = (class_name, operation, identifier)
|
|
179
|
+
if storage.seen_dependencies_stack_version != storage.stack_version:
|
|
180
|
+
storage.seen_dependencies.clear()
|
|
181
|
+
storage.seen_dependencies_stack_version = storage.stack_version
|
|
182
|
+
elif dependency in storage.seen_dependencies:
|
|
183
|
+
return
|
|
184
|
+
if storage.depth == 0:
|
|
185
|
+
storage.dependencies[0].add(dependency)
|
|
186
|
+
else:
|
|
187
|
+
for dep_set in storage.dependencies:
|
|
188
|
+
dep_set.add(dependency)
|
|
189
|
+
storage.last_dependency = dependency
|
|
190
|
+
storage.last_dependency_stack_version = storage.stack_version
|
|
191
|
+
storage.seen_dependencies.add(dependency)
|
|
192
|
+
|
|
193
|
+
@staticmethod
|
|
194
|
+
def _track_many_validated(dependencies: Iterable[Dependency]) -> None:
|
|
195
|
+
"""Record already-validated dependency tuples in active collectors."""
|
|
196
|
+
if _dependency_storage.depth < 0:
|
|
197
|
+
return
|
|
198
|
+
reusable_dependencies: Collection[Dependency]
|
|
199
|
+
if isinstance(dependencies, Collection):
|
|
200
|
+
reusable_dependencies = dependencies
|
|
201
|
+
else:
|
|
202
|
+
reusable_dependencies = tuple(dependencies)
|
|
150
203
|
for dep_set in _dependency_storage.dependencies:
|
|
151
|
-
dep_set.
|
|
204
|
+
dep_set.update(reusable_dependencies)
|
|
205
|
+
|
|
206
|
+
@staticmethod
|
|
207
|
+
def _dependencies_are_tracker_captured(dependencies: object) -> bool:
|
|
208
|
+
"""Return whether dependencies came from this tracker implementation."""
|
|
209
|
+
return isinstance(dependencies, _TrackedDependencySet)
|
|
152
210
|
|
|
153
211
|
@staticmethod
|
|
154
212
|
def is_active() -> bool:
|