GeneralManager 0.68.2__tar.gz → 0.69.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {generalmanager-0.68.2/src/GeneralManager.egg-info → generalmanager-0.69.0}/PKG-INFO +1 -1
- {generalmanager-0.68.2 → generalmanager-0.69.0}/pyproject.toml +1 -1
- {generalmanager-0.68.2 → generalmanager-0.69.0/src/GeneralManager.egg-info}/PKG-INFO +1 -1
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql.py +37 -29
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_resolvers.py +4 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/remote_invalidation.py +25 -17
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/data_change_context.py +77 -6
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/dependency_index.py +32 -21
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/signals.py +88 -14
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/invalidation.py +50 -44
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/signal_bridge.py +22 -13
- {generalmanager-0.68.2 → generalmanager-0.69.0}/LICENSE +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/README.md +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/setup.cfg +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/GeneralManager.egg-info/SOURCES.txt +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/GeneralManager.egg-info/dependency_links.txt +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/GeneralManager.egg-info/requires.txt +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/GeneralManager.egg-info/top_level.txt +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/api.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/bucket.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/cache.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/dataframes.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/factory.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/general_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/interface.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/measurement.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/permission.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/rule.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/search.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/_types/utils.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_as_of.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_errors.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_mutations.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_prefetch.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_relations.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_search.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_subscription_consumer.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_subscriptions.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_view.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_warmup.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_warmup_registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_warmup_tasks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/mutation.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/notification_batching.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/property.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/remote_api.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/remote_invalidation_client.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/apps.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/as_of.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bootstrap.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/base_bucket.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/calculation_bucket.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/database_bucket.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/group_bucket.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/indexing.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/bucket/request_bucket.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/cache_decorator.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/cache_tracker.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/dependency_cache.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/dependency_matching.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/dependency_publish.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/dependency_shards.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/model_dependency_collector.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/run_context.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/run_context_lru.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/audit.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/bootstrap.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/checks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/consumer.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/errors.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/__main__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/baseline.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/datasets/basic_queries.yaml +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/datasets/demo_readiness.yaml +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/datasets/edge_cases.yaml +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/datasets/follow_ups.yaml +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/datasets/large_schema.yaml +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/datasets/multi_hop.yaml +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/diagnostics.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/fingerprints.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/fixtures.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/judges/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/judges/answer_quality.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/judges/contract.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/judges/result_accuracy.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/judges/tool_sequence.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/readiness.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/runner.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/evals/traces.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/grounding.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/_shared.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/anthropic.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/base.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/google.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/ollama.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/providers/openai.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/rate_limits.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/routing.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/schema_index.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/settings.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/signals.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/system_prompt.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/tool_metadata.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/tools.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/chat/views.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/conf.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/dataframes/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/dataframes/measurements.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/factory/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/factory/auto_factory.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/factory/factories.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/factory/factory_methods.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/base_interface.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/bundles/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/bundles/calculation.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/bundles/database.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/bundles/remote_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/bundles/request.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/base.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/builtin.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/calculation/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/calculation/_compat.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/calculation/lifecycle.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/configuration.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/core/observability.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/core/utils.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/exceptions.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/existing_model/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/existing_model/_compat.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/existing_model/resolution.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/factory.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm/_compat.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm/history.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm/lifecycle.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm/mutations.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm/support.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm_utils/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm_utils/django_manager_utils.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm_utils/field_descriptors.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/orm_utils/payload_normalizer.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/read_only/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/read_only/_compat.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/read_only/_types.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/read_only/lifecycle.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/read_only/management.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/remote_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/capabilities/request/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/infrastructure/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/infrastructure/startup_hooks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/infrastructure/system_checks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/calculation.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/database.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/existing_model.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/read_only.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/remote_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/interfaces/request.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/manifests/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/manifests/capability_builder.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/manifests/capability_manifest.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/manifests/capability_models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/orm_interface.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/requests.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/utils/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/utils/database_interface_protocols.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/utils/errors.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/utils/history.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/interface/utils/models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/logging.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/chat_cleanup.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/cleanup_upload_intents.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/graphql_warmup.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/graphql_warmup_refresh_due.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/search_index.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/search_reconcile.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/seed_manager_landscape.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/shell.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/workflow_drain_outbox.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/management/commands/workflow_replay_dead_letters.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/manager/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/manager/general_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/manager/group_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/manager/input.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/manager/meta.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/measurement/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/measurement/measurement.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/measurement/measurement_field.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/metrics/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/metrics/graphql.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0001_initial.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0002_workflow_outbox_scaling_indexes.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0003_workflow_execution_correlation_constraint.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0004_chat_persistence_models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0004_search_index_state.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0005_merge_chat_search.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0006_chat_pending_confirmation_scoped_ids.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0007_upload_intent.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0008_upload_finalization_versions.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0009_upload_cleanup_state.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0010_chat_pending_confirmation_portable_uniqueness.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/0011_search_index_state_dirty_generation.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/migrations/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/audit.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/base_permission.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/graphql_capabilities.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/manager_based_permission.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/mutation_permission.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/permission_checks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/permission_data_manager.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/permission/utils.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/public_api_registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/py.typed +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/rule/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/rule/handler.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/rule/rule.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/async_tasks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backend.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backend_registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backends/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backends/dev.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backends/meilisearch.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backends/opensearch.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/backends/typesense.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/checks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/config.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/indexer.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/m2m_invalidation.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/reconciliation.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/tasks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/search/utils.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/seeding/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/seeding/manager_landscape.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/adapters.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/checks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/config.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/errors.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/finalization.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/graphql.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/graphql_types.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/metrics.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/public.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/s3.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/services.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/tokens.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/types.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/urls.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/uploads/views.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/args_to_kwargs.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/filter_parser.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/format_string.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/json_encoder.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/make_cache_key.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/none_to_zero.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/path_mapping.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/public_api.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/testing.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/utils/type_checks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/actions.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/backend_registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/backends/__init__.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/backends/celery.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/backends/local.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/backends/n8n.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/config.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/engine.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/event_registry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/events.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/models.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/tasks.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/workflow/telemetry.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/tests/test_settings.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/tests/test_urls.py +0 -0
- {generalmanager-0.68.2 → generalmanager-0.69.0}/tests/testing_asgi.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.69.0
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "GeneralManager"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.69.0"
|
|
8
8
|
description = "Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [{ name = "Tim Kleindick", email = "tkleindick@yahoo.de" }]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: GeneralManager
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.69.0
|
|
4
4
|
Summary: Modular Django-based data management framework with ORM, GraphQL, fine-grained permissions, rule validation, calculations and caching.
|
|
5
5
|
Author-email: Tim Kleindick <tkleindick@yahoo.de>
|
|
6
6
|
License: MIT License
|
|
@@ -6,6 +6,7 @@ import asyncio
|
|
|
6
6
|
from contextlib import asynccontextmanager
|
|
7
7
|
from copy import deepcopy
|
|
8
8
|
import re
|
|
9
|
+
from time import perf_counter
|
|
9
10
|
from types import UnionType
|
|
10
11
|
from typing import (
|
|
11
12
|
AsyncIterator,
|
|
@@ -37,6 +38,7 @@ from general_manager.bucket.group_bucket import GroupBucket
|
|
|
37
38
|
from general_manager.cache.dependency_index import (
|
|
38
39
|
Dependency,
|
|
39
40
|
)
|
|
41
|
+
from general_manager.cache.data_change_context import record_data_change_phase
|
|
40
42
|
from general_manager.cache.signals import post_data_change
|
|
41
43
|
from general_manager.conf import get_setting
|
|
42
44
|
from general_manager.interface.base_interface import InterfaceBase
|
|
@@ -1784,38 +1786,44 @@ class GraphQL:
|
|
|
1784
1786
|
instance (GeneralManager | None): The GeneralManager instance that changed.
|
|
1785
1787
|
action (str): A string describing the change action (e.g., "created", "updated", "deleted").
|
|
1786
1788
|
"""
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1789
|
+
started = perf_counter()
|
|
1790
|
+
try:
|
|
1791
|
+
event_instance = instance if instance is not None else previous_instance
|
|
1792
|
+
if event_instance is None or not isinstance(event_instance, GeneralManager):
|
|
1793
|
+
return
|
|
1790
1794
|
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
+
if isinstance(sender, type) and issubclass(sender, GeneralManager):
|
|
1796
|
+
manager_class: type[GeneralManager] = sender
|
|
1797
|
+
else:
|
|
1798
|
+
manager_class = event_instance.__class__
|
|
1795
1799
|
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1800
|
+
if manager_class.__name__ not in cls.manager_registry:
|
|
1801
|
+
logger.debug(
|
|
1802
|
+
"skipping subscription event for unregistered manager",
|
|
1803
|
+
context={
|
|
1804
|
+
"manager": manager_class.__name__,
|
|
1805
|
+
"action": action,
|
|
1806
|
+
},
|
|
1807
|
+
)
|
|
1808
|
+
return
|
|
1805
1809
|
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1810
|
+
event_identification = deepcopy(
|
|
1811
|
+
identification
|
|
1812
|
+
if identification is not None
|
|
1813
|
+
else event_instance.identification
|
|
1814
|
+
)
|
|
1815
|
+
transaction.on_commit(
|
|
1816
|
+
lambda: cls._publish_data_change(
|
|
1817
|
+
manager_class,
|
|
1818
|
+
action,
|
|
1819
|
+
event_identification,
|
|
1820
|
+
),
|
|
1821
|
+
using=database_alias,
|
|
1822
|
+
)
|
|
1823
|
+
finally:
|
|
1824
|
+
record_data_change_phase(
|
|
1825
|
+
"subscription", perf_counter() - started, database_alias
|
|
1826
|
+
)
|
|
1819
1827
|
|
|
1820
1828
|
@classmethod
|
|
1821
1829
|
def _publish_data_change(
|
{generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/graphql_resolvers.py
RENAMED
|
@@ -499,6 +499,8 @@ def apply_pagination(
|
|
|
499
499
|
Negative ``page`` or ``page_size`` values raise ``ValueError`` before
|
|
500
500
|
slicing. Falsey explicit values such as ``page=0`` or ``page_size=0`` also
|
|
501
501
|
fall back through those defaults for slicing.
|
|
502
|
+
Already-empty grouped buckets are returned unchanged when pagination is
|
|
503
|
+
requested, preserving their shape without invoking an invalid empty slice.
|
|
502
504
|
The returned object keeps the same bucket/group-bucket shape as the slice
|
|
503
505
|
operation exposes. Slice errors from the bucket implementation propagate
|
|
504
506
|
unchanged.
|
|
@@ -508,6 +510,8 @@ def apply_pagination(
|
|
|
508
510
|
if page_size is not None and page_size < 0:
|
|
509
511
|
raise InvalidPaginationValueError
|
|
510
512
|
if page is not None or page_size is not None:
|
|
513
|
+
if isinstance(queryset, GroupBucket) and len(queryset) == 0:
|
|
514
|
+
return queryset
|
|
511
515
|
page = page or 1
|
|
512
516
|
page_size = page_size or 10
|
|
513
517
|
offset = (page - 1) * page_size
|
{generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/api/remote_invalidation.py
RENAMED
|
@@ -8,6 +8,7 @@ from datetime import date, datetime
|
|
|
8
8
|
import json
|
|
9
9
|
from importlib import import_module
|
|
10
10
|
import re
|
|
11
|
+
from time import perf_counter
|
|
11
12
|
from uuid import UUID, uuid4
|
|
12
13
|
from collections.abc import Callable, Coroutine, Mapping, MutableSequence, Sequence
|
|
13
14
|
from types import ModuleType
|
|
@@ -25,6 +26,7 @@ from general_manager.api.remote_api import (
|
|
|
25
26
|
get_remote_api_config,
|
|
26
27
|
)
|
|
27
28
|
from general_manager.api.notification_batching import _queue_notification
|
|
29
|
+
from general_manager.cache.data_change_context import record_data_change_phase
|
|
28
30
|
from general_manager.cache.signals import post_data_change
|
|
29
31
|
from general_manager.logging import get_logger
|
|
30
32
|
|
|
@@ -200,24 +202,30 @@ def emit_remote_invalidation(
|
|
|
200
202
|
originating database alias and delegates channel lookup, batching, payload
|
|
201
203
|
creation, and delivery to `_publish_remote_invalidation` after commit.
|
|
202
204
|
"""
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
205
|
+
started = perf_counter()
|
|
206
|
+
try:
|
|
207
|
+
config = get_remote_api_config(sender)
|
|
208
|
+
if config is None or not config.websocket_invalidation:
|
|
209
|
+
return
|
|
206
210
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
211
|
+
event_identification = identification
|
|
212
|
+
if event_identification is None and instance is not None:
|
|
213
|
+
event_identification = dict(instance.identification)
|
|
214
|
+
captured_identification = (
|
|
215
|
+
deepcopy(event_identification) if event_identification is not None else None
|
|
216
|
+
)
|
|
217
|
+
transaction.on_commit(
|
|
218
|
+
lambda: _publish_remote_invalidation(
|
|
219
|
+
config,
|
|
220
|
+
action,
|
|
221
|
+
captured_identification,
|
|
222
|
+
),
|
|
223
|
+
using=database_alias,
|
|
224
|
+
)
|
|
225
|
+
finally:
|
|
226
|
+
record_data_change_phase(
|
|
227
|
+
"subscription", perf_counter() - started, database_alias
|
|
228
|
+
)
|
|
221
229
|
|
|
222
230
|
|
|
223
231
|
post_data_change.connect(emit_remote_invalidation, weak=False)
|
{generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/data_change_context.py
RENAMED
|
@@ -5,17 +5,45 @@ from __future__ import annotations
|
|
|
5
5
|
from collections.abc import Iterator
|
|
6
6
|
from contextlib import contextmanager
|
|
7
7
|
from contextvars import ContextVar
|
|
8
|
-
from dataclasses import dataclass
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from math import isfinite
|
|
10
|
+
from typing import Literal
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class DataChangeTransactionContext:
|
|
15
|
+
"""Mutable state owned by one framework-managed data-change transaction."""
|
|
16
|
+
|
|
17
|
+
database_alias: str
|
|
18
|
+
caller_in_atomic_block: bool
|
|
19
|
+
changed_classes: set[str] = field(default_factory=set)
|
|
20
|
+
metadata: dict[str, object] = field(default_factory=dict)
|
|
21
|
+
phase_seconds: dict[str, float] = field(default_factory=dict)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class DataChangeTransactionScope:
|
|
26
|
+
"""Public view of a context-manager entry's transaction state."""
|
|
27
|
+
|
|
28
|
+
transaction: DataChangeTransactionContext
|
|
29
|
+
is_outermost: bool
|
|
9
30
|
|
|
10
31
|
|
|
11
32
|
@dataclass
|
|
12
33
|
class _DataChangeTransaction:
|
|
13
34
|
"""Live marker for one framework-owned transaction envelope."""
|
|
14
35
|
|
|
15
|
-
|
|
16
|
-
caller_in_atomic_block: bool
|
|
36
|
+
context: DataChangeTransactionContext
|
|
17
37
|
active: bool = True
|
|
18
38
|
|
|
39
|
+
@property
|
|
40
|
+
def database_alias(self) -> str:
|
|
41
|
+
return self.context.database_alias
|
|
42
|
+
|
|
43
|
+
@property
|
|
44
|
+
def caller_in_atomic_block(self) -> bool:
|
|
45
|
+
return self.context.caller_in_atomic_block
|
|
46
|
+
|
|
19
47
|
|
|
20
48
|
_owned_transactions: ContextVar[tuple[_DataChangeTransaction, ...]] = ContextVar(
|
|
21
49
|
"owned_data_change_transactions",
|
|
@@ -34,25 +62,68 @@ def _current_owner(database_alias: str) -> _DataChangeTransaction | None:
|
|
|
34
62
|
return None
|
|
35
63
|
|
|
36
64
|
|
|
65
|
+
def current_data_change_transaction(
|
|
66
|
+
database_alias: str,
|
|
67
|
+
) -> DataChangeTransactionContext | None:
|
|
68
|
+
"""Return the live framework-owned context for a database alias, if any."""
|
|
69
|
+
owner = _current_owner(database_alias)
|
|
70
|
+
return owner.context if owner is not None else None
|
|
71
|
+
|
|
72
|
+
|
|
37
73
|
@contextmanager
|
|
38
74
|
def own_data_change_transaction(
|
|
39
75
|
database_alias: str,
|
|
40
76
|
*,
|
|
41
77
|
caller_in_atomic_block: bool,
|
|
42
|
-
) -> Iterator[
|
|
78
|
+
) -> Iterator[DataChangeTransactionScope]:
|
|
43
79
|
"""Record a live framework envelope without inspecting Django internals."""
|
|
44
|
-
|
|
80
|
+
existing_owner = _current_owner(database_alias)
|
|
81
|
+
if existing_owner is not None:
|
|
82
|
+
yield DataChangeTransactionScope(
|
|
83
|
+
transaction=existing_owner.context,
|
|
84
|
+
is_outermost=False,
|
|
85
|
+
)
|
|
86
|
+
return
|
|
87
|
+
|
|
88
|
+
context = DataChangeTransactionContext(
|
|
45
89
|
database_alias=database_alias,
|
|
46
90
|
caller_in_atomic_block=caller_in_atomic_block,
|
|
47
91
|
)
|
|
92
|
+
owner = _DataChangeTransaction(
|
|
93
|
+
context=context,
|
|
94
|
+
)
|
|
48
95
|
token = _owned_transactions.set((*_owned_transactions.get(), owner))
|
|
49
96
|
try:
|
|
50
|
-
yield
|
|
97
|
+
yield DataChangeTransactionScope(transaction=context, is_outermost=True)
|
|
51
98
|
finally:
|
|
52
99
|
owner.active = False
|
|
53
100
|
_owned_transactions.reset(token)
|
|
54
101
|
|
|
55
102
|
|
|
103
|
+
def register_data_change_class(class_name: str, database_alias: str) -> bool:
|
|
104
|
+
"""Record a changed class when the framework owns the live transaction."""
|
|
105
|
+
context = current_data_change_transaction(database_alias)
|
|
106
|
+
if context is None or context.caller_in_atomic_block:
|
|
107
|
+
return False
|
|
108
|
+
context.changed_classes.add(class_name)
|
|
109
|
+
return True
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def record_data_change_phase(
|
|
113
|
+
phase: Literal["database", "invalidation", "subscription", "search", "workflow"],
|
|
114
|
+
duration_seconds: float,
|
|
115
|
+
database_alias: str,
|
|
116
|
+
) -> None:
|
|
117
|
+
"""Accumulate a non-negative duration for a phase in the live context."""
|
|
118
|
+
if not isfinite(duration_seconds):
|
|
119
|
+
return
|
|
120
|
+
context = current_data_change_transaction(database_alias)
|
|
121
|
+
if context is not None:
|
|
122
|
+
context.phase_seconds[phase] = context.phase_seconds.get(phase, 0.0) + max(
|
|
123
|
+
duration_seconds, 0.0
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
|
|
56
127
|
@contextmanager
|
|
57
128
|
def authorize_data_change_operation(database_alias: str) -> Iterator[None]:
|
|
58
129
|
"""Authorize only the decorated manager method to reuse its envelope."""
|
{generalmanager-0.68.2 → generalmanager-0.69.0}/src/general_manager/cache/dependency_index.py
RENAMED
|
@@ -8,9 +8,11 @@ import time
|
|
|
8
8
|
import uuid
|
|
9
9
|
from contextvars import ContextVar
|
|
10
10
|
from datetime import date, datetime
|
|
11
|
+
from time import perf_counter
|
|
11
12
|
from typing import TYPE_CHECKING, Callable, Iterable, Literal, Tuple, Type, cast
|
|
12
13
|
|
|
13
14
|
from django.core.cache import cache
|
|
15
|
+
from django.db import DEFAULT_DB_ALIAS
|
|
14
16
|
from django.dispatch import receiver
|
|
15
17
|
|
|
16
18
|
from general_manager.cache.dependency_matching import (
|
|
@@ -34,6 +36,7 @@ from general_manager.cache.dependency_shards import (
|
|
|
34
36
|
reverse_memberships,
|
|
35
37
|
tracked_lookup_names,
|
|
36
38
|
)
|
|
39
|
+
from general_manager.cache.data_change_context import record_data_change_phase
|
|
37
40
|
from general_manager.cache.signals import post_data_change, pre_data_change
|
|
38
41
|
from general_manager.logging import get_logger
|
|
39
42
|
|
|
@@ -1384,6 +1387,7 @@ def generic_cache_invalidation(
|
|
|
1384
1387
|
sender: type[GeneralManager],
|
|
1385
1388
|
instance: GeneralManager,
|
|
1386
1389
|
old_relevant_values: dict[str, object],
|
|
1390
|
+
database_alias: str = DEFAULT_DB_ALIAS,
|
|
1387
1391
|
**kwargs: object,
|
|
1388
1392
|
) -> None:
|
|
1389
1393
|
"""
|
|
@@ -1395,27 +1399,34 @@ def generic_cache_invalidation(
|
|
|
1395
1399
|
sender (type[GeneralManager]): Manager class that emitted the signal.
|
|
1396
1400
|
instance (GeneralManager): The manager instance that was changed.
|
|
1397
1401
|
old_relevant_values (dict[str, object]): Mapping of lookup paths (joined by "__") to their values as captured before the change; used to compare old vs. new values for invalidation decisions.
|
|
1402
|
+
database_alias (str): Database alias used to attribute invalidation timing.
|
|
1398
1403
|
"""
|
|
1399
|
-
|
|
1400
|
-
invalidated_cache_keys: set[str] = set()
|
|
1401
|
-
lock_token = acquire_lock_with_retry("generic_cache_invalidation")
|
|
1404
|
+
started = perf_counter()
|
|
1402
1405
|
try:
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1406
|
+
manager_name = sender.__name__
|
|
1407
|
+
invalidated_cache_keys: set[str] = set()
|
|
1408
|
+
lock_token = acquire_lock_with_retry("generic_cache_invalidation")
|
|
1409
|
+
try:
|
|
1410
|
+
if legacy_dependency_index_exists():
|
|
1411
|
+
idx = get_full_index()
|
|
1412
|
+
invalidated_cache_keys = _generic_cache_invalidation_locked(
|
|
1413
|
+
idx,
|
|
1414
|
+
manager_name,
|
|
1415
|
+
instance,
|
|
1416
|
+
old_relevant_values,
|
|
1417
|
+
)
|
|
1418
|
+
set_full_index(idx)
|
|
1419
|
+
else:
|
|
1420
|
+
invalidated_cache_keys = _generic_cache_invalidation_from_shards(
|
|
1421
|
+
manager_name,
|
|
1422
|
+
instance,
|
|
1423
|
+
old_relevant_values,
|
|
1424
|
+
)
|
|
1425
|
+
finally:
|
|
1426
|
+
release_lock(lock_token)
|
|
1427
|
+
if invalidated_cache_keys:
|
|
1428
|
+
record_invalidated_cache_keys_for_graphql_rewarm(invalidated_cache_keys)
|
|
1418
1429
|
finally:
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1430
|
+
record_data_change_phase(
|
|
1431
|
+
"invalidation", perf_counter() - started, database_alias
|
|
1432
|
+
)
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
from contextlib import nullcontext
|
|
6
6
|
from copy import deepcopy
|
|
7
7
|
from functools import wraps
|
|
8
|
+
from time import perf_counter
|
|
8
9
|
from typing import Callable, ParamSpec, TypeVar, cast, overload
|
|
9
10
|
|
|
10
11
|
from django.db import DEFAULT_DB_ALIAS, connections, transaction
|
|
@@ -12,8 +13,10 @@ from django.dispatch import Signal
|
|
|
12
13
|
from django.utils.connection import ConnectionDoesNotExist
|
|
13
14
|
|
|
14
15
|
from general_manager.cache.data_change_context import (
|
|
16
|
+
DataChangeTransactionScope,
|
|
15
17
|
authorize_data_change_operation,
|
|
16
18
|
own_data_change_transaction,
|
|
19
|
+
record_data_change_phase,
|
|
17
20
|
)
|
|
18
21
|
from general_manager.as_of import reject_historical_mutation
|
|
19
22
|
from general_manager.logging import get_logger
|
|
@@ -22,6 +25,12 @@ post_data_change = Signal()
|
|
|
22
25
|
|
|
23
26
|
pre_data_change = Signal()
|
|
24
27
|
|
|
28
|
+
data_change_transaction_started = Signal()
|
|
29
|
+
|
|
30
|
+
data_change_transaction_finishing = Signal()
|
|
31
|
+
|
|
32
|
+
data_change_transaction_finished = Signal()
|
|
33
|
+
|
|
25
34
|
P = ParamSpec("P")
|
|
26
35
|
R = TypeVar("R")
|
|
27
36
|
|
|
@@ -64,6 +73,12 @@ def data_change(
|
|
|
64
73
|
data-change barrier has closed; failed mutations drain pending keys but do
|
|
65
74
|
not enqueue rewarm work.
|
|
66
75
|
|
|
76
|
+
ORM-backed outermost mutations also emit transaction lifecycle signals.
|
|
77
|
+
A ``committed`` finished outcome means this GeneralManager atomic block or
|
|
78
|
+
savepoint completed. When ``caller_in_atomic_block`` is true, consumers
|
|
79
|
+
requiring the caller's durable commit must register work with
|
|
80
|
+
``transaction.on_commit()``.
|
|
81
|
+
|
|
67
82
|
Parameters:
|
|
68
83
|
func: Function that performs a data mutation. Methods named `create`
|
|
69
84
|
are treated as class-level creates; every other name is treated as
|
|
@@ -134,6 +149,8 @@ def data_change(
|
|
|
134
149
|
|
|
135
150
|
primary_exc: BaseException | None = None
|
|
136
151
|
completed = False
|
|
152
|
+
transaction_scope: DataChangeTransactionScope | None = None
|
|
153
|
+
transaction_outcome = "rolled_back"
|
|
137
154
|
begin_dependency_data_change()
|
|
138
155
|
context = current_calculation_run_context()
|
|
139
156
|
if context is not None:
|
|
@@ -157,7 +174,30 @@ def data_change(
|
|
|
157
174
|
if is_orm_backed
|
|
158
175
|
else nullcontext()
|
|
159
176
|
)
|
|
160
|
-
with transaction_context, ownership_context:
|
|
177
|
+
with transaction_context, ownership_context as entered_scope:
|
|
178
|
+
if is_orm_backed:
|
|
179
|
+
assert isinstance(entered_scope, DataChangeTransactionScope)
|
|
180
|
+
transaction_scope = entered_scope
|
|
181
|
+
lifecycle_action = (
|
|
182
|
+
action if action in {"create", "update", "delete"} else "other"
|
|
183
|
+
)
|
|
184
|
+
lifecycle_kwargs = (
|
|
185
|
+
{
|
|
186
|
+
"transaction_context": transaction_scope.transaction,
|
|
187
|
+
"database_alias": database_alias,
|
|
188
|
+
"caller_in_atomic_block": (
|
|
189
|
+
transaction_scope.transaction.caller_in_atomic_block
|
|
190
|
+
),
|
|
191
|
+
"action": lifecycle_action,
|
|
192
|
+
}
|
|
193
|
+
if transaction_scope is not None
|
|
194
|
+
else {}
|
|
195
|
+
)
|
|
196
|
+
if transaction_scope is not None and transaction_scope.is_outermost:
|
|
197
|
+
data_change_transaction_started.send(
|
|
198
|
+
sender=sender,
|
|
199
|
+
**lifecycle_kwargs,
|
|
200
|
+
)
|
|
161
201
|
pre_data_change.send(
|
|
162
202
|
sender=sender,
|
|
163
203
|
instance=instance_before,
|
|
@@ -174,11 +214,22 @@ def data_change(
|
|
|
174
214
|
else nullcontext()
|
|
175
215
|
)
|
|
176
216
|
with operation_context:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
217
|
+
mutation_started = (
|
|
218
|
+
perf_counter() if transaction_scope is not None else None
|
|
219
|
+
)
|
|
220
|
+
try:
|
|
221
|
+
if isinstance(func, classmethod):
|
|
222
|
+
inner = cast(Callable[P, R], func.__func__)
|
|
223
|
+
result = inner(*args, **kwargs)
|
|
224
|
+
else:
|
|
225
|
+
result = func(*args, **kwargs)
|
|
226
|
+
finally:
|
|
227
|
+
if mutation_started is not None:
|
|
228
|
+
record_data_change_phase(
|
|
229
|
+
"database",
|
|
230
|
+
perf_counter() - mutation_started,
|
|
231
|
+
database_alias,
|
|
232
|
+
)
|
|
182
233
|
|
|
183
234
|
context = current_calculation_run_context()
|
|
184
235
|
if context is not None:
|
|
@@ -205,6 +256,13 @@ def data_change(
|
|
|
205
256
|
delattr(instance_before, "_old_values")
|
|
206
257
|
except AttributeError:
|
|
207
258
|
pass
|
|
259
|
+
if transaction_scope is not None and transaction_scope.is_outermost:
|
|
260
|
+
data_change_transaction_finishing.send(
|
|
261
|
+
sender=sender,
|
|
262
|
+
**lifecycle_kwargs,
|
|
263
|
+
)
|
|
264
|
+
if transaction_scope is not None and transaction_scope.is_outermost:
|
|
265
|
+
transaction_outcome = "committed"
|
|
208
266
|
completed = True
|
|
209
267
|
except BaseException as error:
|
|
210
268
|
primary_exc = error
|
|
@@ -215,15 +273,31 @@ def data_change(
|
|
|
215
273
|
cache_keys: tuple[str, ...] = ()
|
|
216
274
|
try:
|
|
217
275
|
try:
|
|
276
|
+
if transaction_scope is not None and transaction_scope.is_outermost:
|
|
277
|
+
try:
|
|
278
|
+
lifecycle_kwargs["outcome"] = transaction_outcome
|
|
279
|
+
data_change_transaction_finished.send(
|
|
280
|
+
sender=sender,
|
|
281
|
+
**lifecycle_kwargs,
|
|
282
|
+
)
|
|
283
|
+
except Exception:
|
|
284
|
+
if primary_exc is not None:
|
|
285
|
+
logger.exception(
|
|
286
|
+
"Data-change transaction finished receiver failed "
|
|
287
|
+
"while handling another exception."
|
|
288
|
+
)
|
|
289
|
+
else:
|
|
290
|
+
raise
|
|
291
|
+
finally:
|
|
218
292
|
end_dependency_data_change()
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
293
|
+
except Exception:
|
|
294
|
+
if primary_exc is not None:
|
|
295
|
+
logger.exception(
|
|
296
|
+
"Dependency data-change cleanup failed while handling "
|
|
297
|
+
"another exception."
|
|
298
|
+
)
|
|
299
|
+
else:
|
|
300
|
+
raise
|
|
227
301
|
finally:
|
|
228
302
|
try:
|
|
229
303
|
if not is_dependency_data_change_active():
|