quantum-framework 0.10.0__tar.gz → 0.12.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.
- {quantum_framework-0.10.0/quantum_framework.egg-info → quantum_framework-0.12.0}/PKG-INFO +6 -2
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/README.md +1 -1
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/pyproject.toml +16 -2
- quantum_framework-0.12.0/quantum/cli/admin.py +131 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/migrate.py +62 -81
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/runner.py +15 -35
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/ast_nodes.py +2 -0
- quantum_framework-0.12.0/quantum/core/config_env.py +54 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/expressions.py +64 -43
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/data_import/src/ast_node.py +1 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/invocation/src/ast_node.py +1 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/invocation/src/runtime.py +8 -3
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parser.py +186 -1
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/data/data_parser.py +9 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/data/invoke_parser.py +13 -1
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/data/query_parser.py +11 -6
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/data/transaction_parser.py +9 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/functions/function_parser.py +22 -68
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/tiers.py +18 -7
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/__init__.py +0 -3
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/action_handler.py +28 -11
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/component.py +137 -88
- quantum_framework-0.12.0/quantum/runtime/component_composer.py +133 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/control_flow/set_executor.py +91 -39
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/data/data_executor.py +8 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/data/invoke_executor.py +70 -18
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/param_validation.py +8 -6
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/renderer.py +32 -25
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/service_container.py +5 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/web_server.py +61 -18
- quantum_framework-0.12.0/quantum/services.py +109 -0
- quantum_framework-0.12.0/quantum_admin/__init__.py +4 -0
- quantum_framework-0.12.0/quantum_admin/assets/quantum-admin-connectors.js +123 -0
- quantum_framework-0.12.0/quantum_admin/assets/quantum-admin.css +2058 -0
- quantum_framework-0.12.0/quantum_admin/assets/quantum-source-highlight.js +106 -0
- quantum_framework-0.12.0/quantum_admin/backend/__init__.py +4 -0
- quantum_framework-0.12.0/quantum_admin/backend/audit_service.py +346 -0
- quantum_framework-0.12.0/quantum_admin/backend/auth_service.py +394 -0
- quantum_framework-0.12.0/quantum_admin/backend/component_discovery.py +766 -0
- quantum_framework-0.12.0/quantum_admin/backend/config_generator.py +586 -0
- quantum_framework-0.12.0/quantum_admin/backend/connector_service.py +1016 -0
- quantum_framework-0.12.0/quantum_admin/backend/crud.py +557 -0
- quantum_framework-0.12.0/quantum_admin/backend/database.py +226 -0
- quantum_framework-0.12.0/quantum_admin/backend/db_setup_service.py +193 -0
- quantum_framework-0.12.0/quantum_admin/backend/deploy_service.py +698 -0
- quantum_framework-0.12.0/quantum_admin/backend/docker_service.py +422 -0
- quantum_framework-0.12.0/quantum_admin/backend/environment_service.py +418 -0
- quantum_framework-0.12.0/quantum_admin/backend/git_service.py +370 -0
- quantum_framework-0.12.0/quantum_admin/backend/health_service.py +390 -0
- quantum_framework-0.12.0/quantum_admin/backend/job_service.py +347 -0
- quantum_framework-0.12.0/quantum_admin/backend/log_service.py +331 -0
- quantum_framework-0.12.0/quantum_admin/backend/main.py +14426 -0
- quantum_framework-0.12.0/quantum_admin/backend/models.py +986 -0
- quantum_framework-0.12.0/quantum_admin/backend/pipeline_service.py +812 -0
- quantum_framework-0.12.0/quantum_admin/backend/resource_manager.py +1118 -0
- quantum_framework-0.12.0/quantum_admin/backend/schemas.py +419 -0
- quantum_framework-0.12.0/quantum_admin/backend/secret_manager.py +277 -0
- quantum_framework-0.12.0/quantum_admin/backend/settings_service.py +488 -0
- quantum_framework-0.12.0/quantum_admin/backend/template_service.py +710 -0
- quantum_framework-0.12.0/quantum_admin/backend/test_execution_service.py +364 -0
- quantum_framework-0.12.0/quantum_admin/backend/test_generator.py +782 -0
- quantum_framework-0.12.0/quantum_admin/backend/webhook_service.py +454 -0
- quantum_framework-0.12.0/quantum_admin/backend/websocket_manager.py +360 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/_layout/AdminShell.q +121 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/agents.q +107 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/app/[name].q +558 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/applications.q +160 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/component/[...path].q +205 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/components.q +59 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/connectors.q +283 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/dashboard.q +86 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/database.q +95 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/features.q +69 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/index.q +12 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/jobs.q +75 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/login.q +65 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/logout.q +11 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/settings.q +174 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/source.q +45 -0
- quantum_framework-0.12.0/quantum_admin/components/admin/tests.q +73 -0
- quantum_framework-0.12.0/quantum_admin/run.py +13 -0
- quantum_framework-0.12.0/quantum_admin/services/__init__.py +16 -0
- quantum_framework-0.12.0/quantum_admin/services/_base.py +84 -0
- quantum_framework-0.12.0/quantum_admin/services/_component_test_generator.py +205 -0
- quantum_framework-0.12.0/quantum_admin/services/_yaml_editor.py +82 -0
- quantum_framework-0.12.0/quantum_admin/services/apps.py +330 -0
- quantum_framework-0.12.0/quantum_admin/services/auth.py +61 -0
- quantum_framework-0.12.0/quantum_admin/services/components.py +210 -0
- quantum_framework-0.12.0/quantum_admin/services/connectors.py +164 -0
- quantum_framework-0.12.0/quantum_admin/services/projects.py +189 -0
- quantum_framework-0.12.0/quantum_admin/services/repository.py +223 -0
- quantum_framework-0.12.0/quantum_admin/services/settings.py +150 -0
- quantum_framework-0.12.0/quantum_admin/services/yaml_import.py +118 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0/quantum_framework.egg-info}/PKG-INFO +6 -2
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum_framework.egg-info/SOURCES.txt +65 -7
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum_framework.egg-info/requires.txt +5 -0
- quantum_framework-0.12.0/quantum_framework.egg-info/top_level.txt +2 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_game_engine.py +2 -2
- quantum_framework-0.10.0/quantum/core/features/data_fetching/src/__init__.py +0 -21
- quantum_framework-0.10.0/quantum/core/features/data_fetching/src/ast_node.py +0 -312
- quantum_framework-0.10.0/quantum/core/features/data_fetching/src/desktop_adapter.py +0 -351
- quantum_framework-0.10.0/quantum/core/features/data_fetching/src/html_adapter.py +0 -474
- quantum_framework-0.10.0/quantum/core/features/data_fetching/src/parser.py +0 -225
- quantum_framework-0.10.0/quantum/runtime/api_server.py +0 -86
- quantum_framework-0.10.0/quantum/runtime/component_composer.py +0 -319
- quantum_framework-0.10.0/quantum_framework.egg-info/top_level.txt +0 -1
- quantum_framework-0.10.0/tests/test_data_fetching.py +0 -593
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/LICENSE +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/build.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/dev.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/docs.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/lint.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/new.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/serve.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/commands/test.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/deploy.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/hot_reload.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/jobs.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/mq.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/pkg.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/server_process.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/cli/utils.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/base_generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/cli.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/expression_transformer.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/javascript/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/javascript/generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/optimizer.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/python/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/python/generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/python/runtime.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/compiler/transpiler.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/expression_diagnostics.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/expression_stdlib.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/agents/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/agents/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/data_import/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/data_import/src/runtime.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/dump/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/dump/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/dump/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/dump/src/runtime.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/functions/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/functions/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/invocation/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/logging/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/logging/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/logging/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/logging/src/runtime.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/loops/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/loops/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/query/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/query/src/database_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/query/src/query_validators.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/state_management/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/theming/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/theming/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/theming/src/presets.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/ui_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/ui_engine/src/parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/websocket/src/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/html_compat.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parser_registry.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/ai/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/ai/agent_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/ai/llm_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/ai/team_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/base.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/composition/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/composition/import_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/control_flow/if_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/control_flow/set_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/data/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/events/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/forms/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/forms/action_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/functions/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/functions/param_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/functions/return_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/html/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/html/html_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/jobs/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/messaging/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/persistence/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/persistence/persist_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/routing/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/routing/route_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/scripting/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/services/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/services/dump_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/services/file_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/services/log_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/core/parsers/services/mail_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/packages/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/packages/manager.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/packages/manifest.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/packages/registry.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/packages/resolver.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/plugins/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/plugins/hooks.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/plugins/loader.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/plugins/manifest.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/plugins/registry.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/adapters/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/agent_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ast_cache.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/auth_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/component_resolver.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/database_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/email_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/error_handler.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/execution_context.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executor_registry.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/ai/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/ai/agent_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/ai/llm_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/base.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/control_flow/if_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/control_flow/loop_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/data/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/data/query_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/services/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/services/file_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/services/log_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/expression_cache.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/file_upload_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/function_registry.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/game_builder.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/game_code_generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/game_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/godot_code_generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/godot_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/job_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/knowledge_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/llm_cache.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/llm_providers.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/llm_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/logging_setup.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/message_broker.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/message_queue_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/pypy_compat.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/python_bridge.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/query_validators.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/terminal_builder.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/terminal_code_generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/terminal_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/testing_builder.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/testing_code_generator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/testing_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_builder.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_desktop_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_desktop_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_html_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_html_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_mobile_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_textual_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_textual_templates.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_tokens.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/ui_validator.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/validators.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/websocket_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/websocket_service.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/websocket_transport.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/runtime/wsgi.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum/utils/__init__.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/quantum_framework.egg-info/entry_points.txt +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/setup.cfg +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_agent.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_animations.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_ast_cache.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_cli_commands.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_component_library.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_desktop_bridge.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_expression_cache.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_form_validation.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_game_codegen.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_game_e2e.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_game_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_godot_codegen.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_job_executor.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_llm_providers.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_message_broker.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_message_queue.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_mobile_target.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_multi_agent.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_packages.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_plugins.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_projects_blog_components_admin.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_pypy_compat.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_python_scripting.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_state_persistence.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_terminal_codegen.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_terminal_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_testing_codegen.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_testing_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_theming.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_ui_html_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_ui_parity.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_ui_parser.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_ui_textual_adapter.py +0 -0
- {quantum_framework-0.10.0 → quantum_framework-0.12.0}/tests/test_websocket.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantum-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Full-stack declarative framework for building web, desktop, and mobile applications
|
|
5
5
|
Author-email: Daniel Gregorio <danielgregorio2611@gmail.com>
|
|
6
6
|
License: MIT
|
|
@@ -37,6 +37,10 @@ Provides-Extra: rag
|
|
|
37
37
|
Requires-Dist: chromadb>=0.5.0; extra == "rag"
|
|
38
38
|
Provides-Extra: jobs
|
|
39
39
|
Requires-Dist: apscheduler>=3.10.0; extra == "jobs"
|
|
40
|
+
Provides-Extra: admin
|
|
41
|
+
Requires-Dist: sqlalchemy>=2.0; extra == "admin"
|
|
42
|
+
Requires-Dist: PyJWT>=2.8; extra == "admin"
|
|
43
|
+
Requires-Dist: cryptography>=42.0; extra == "admin"
|
|
40
44
|
Provides-Extra: websocket
|
|
41
45
|
Requires-Dist: websockets>=12.0; extra == "websocket"
|
|
42
46
|
Dynamic: license-file
|
|
@@ -216,7 +220,7 @@ Full docs at **[danielgregorio.github.io/quantum](https://danielgregorio.github.
|
|
|
216
220
|
|
|
217
221
|
- [Getting Started](https://danielgregorio.github.io/quantum/guide/getting-started) · [Installation](https://danielgregorio.github.io/quantum/guide/installation) · [Quick Start](https://danielgregorio.github.io/quantum/guide/quick-start)
|
|
218
222
|
- [Components](https://danielgregorio.github.io/quantum/guide/components) · [State](https://danielgregorio.github.io/quantum/guide/state-management) · [Loops](https://danielgregorio.github.io/quantum/guide/loops) · [Conditionals](https://danielgregorio.github.io/quantum/guide/conditionals)
|
|
219
|
-
- [Queries](https://danielgregorio.github.io/quantum/guide/query) · [Functions](https://danielgregorio.github.io/quantum/guide/functions)
|
|
223
|
+
- [Queries](https://danielgregorio.github.io/quantum/guide/query) · [Functions](https://danielgregorio.github.io/quantum/guide/functions)
|
|
220
224
|
|
|
221
225
|
Releases and their notes are on the [GitHub Releases](https://github.com/danielgregorio/quantum/releases) page.
|
|
222
226
|
|
|
@@ -173,7 +173,7 @@ Full docs at **[danielgregorio.github.io/quantum](https://danielgregorio.github.
|
|
|
173
173
|
|
|
174
174
|
- [Getting Started](https://danielgregorio.github.io/quantum/guide/getting-started) · [Installation](https://danielgregorio.github.io/quantum/guide/installation) · [Quick Start](https://danielgregorio.github.io/quantum/guide/quick-start)
|
|
175
175
|
- [Components](https://danielgregorio.github.io/quantum/guide/components) · [State](https://danielgregorio.github.io/quantum/guide/state-management) · [Loops](https://danielgregorio.github.io/quantum/guide/loops) · [Conditionals](https://danielgregorio.github.io/quantum/guide/conditionals)
|
|
176
|
-
- [Queries](https://danielgregorio.github.io/quantum/guide/query) · [Functions](https://danielgregorio.github.io/quantum/guide/functions)
|
|
176
|
+
- [Queries](https://danielgregorio.github.io/quantum/guide/query) · [Functions](https://danielgregorio.github.io/quantum/guide/functions)
|
|
177
177
|
|
|
178
178
|
Releases and their notes are on the [GitHub Releases](https://github.com/danielgregorio/quantum/releases) page.
|
|
179
179
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "quantum-framework"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.12.0"
|
|
8
8
|
description = "Full-stack declarative framework for building web, desktop, and mobile applications"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = {text = "MIT"}
|
|
@@ -50,6 +50,13 @@ jobs = [
|
|
|
50
50
|
# q:schedule failed on any clean install.
|
|
51
51
|
"apscheduler>=3.10.0",
|
|
52
52
|
]
|
|
53
|
+
admin = [
|
|
54
|
+
# `quantum admin`: the admin database (SQLAlchemy), its login tokens
|
|
55
|
+
# (PyJWT) and encrypted connector secrets (cryptography).
|
|
56
|
+
"sqlalchemy>=2.0",
|
|
57
|
+
"PyJWT>=2.8",
|
|
58
|
+
"cryptography>=42.0",
|
|
59
|
+
]
|
|
53
60
|
websocket = [
|
|
54
61
|
# The transport behind q:websocket. Without it the tag registers a
|
|
55
62
|
# connection and opens nothing — and says so, rather than pretending.
|
|
@@ -71,7 +78,14 @@ Repository = "https://github.com/danielgregorio/quantum"
|
|
|
71
78
|
# do core), e as pastas `quantum-as4`/`quantum-lsp` (projetos irmaos,
|
|
72
79
|
# hifenados e nem importaveis) — 91 arquivos de peso morto no wheel. O ponto
|
|
73
80
|
# em `quantum.*` casa subpacotes; sem ele, `quantum_admin` nao entra.
|
|
74
|
-
include = ["quantum", "quantum.*"
|
|
81
|
+
include = ["quantum", "quantum.*",
|
|
82
|
+
# The admin (`quantum admin`, extra [admin]): its screens, its
|
|
83
|
+
# services and the backend library they use. The backend's
|
|
84
|
+
# FastAPI modules ship with it, unused by the screens.
|
|
85
|
+
"quantum_admin", "quantum_admin.services", "quantum_admin.backend"]
|
|
86
|
+
|
|
87
|
+
[tool.setuptools.package-data]
|
|
88
|
+
quantum_admin = ["components/**/*.q", "assets/*"]
|
|
75
89
|
|
|
76
90
|
|
|
77
91
|
[tool.black]
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
"""`quantum admin` — serve the Quantum Admin (quantum_admin/components/admin).
|
|
2
|
+
|
|
3
|
+
The admin is a Quantum app: .q screens over declared services. This command
|
|
4
|
+
writes its configuration into a data folder and starts the same server as
|
|
5
|
+
`quantum start`, so nothing has to be set up by hand.
|
|
6
|
+
|
|
7
|
+
quantum admin # data in ./.quantum-admin, projects under ./
|
|
8
|
+
quantum admin --data quantum_admin # the repository's own admin data
|
|
9
|
+
|
|
10
|
+
The data folder holds the admin database, its settings (connectors, global
|
|
11
|
+
settings, process PIDs) and the generated config. Paths of projects are
|
|
12
|
+
relative to the folder the command runs in (--root to change it).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import secrets
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
MODULES = [
|
|
20
|
+
"quantum_admin.services.auth",
|
|
21
|
+
"quantum_admin.services.projects",
|
|
22
|
+
"quantum_admin.services.yaml_import",
|
|
23
|
+
"quantum_admin.services.connectors",
|
|
24
|
+
"quantum_admin.services.settings",
|
|
25
|
+
"quantum_admin.services.components",
|
|
26
|
+
"quantum_admin.services.apps",
|
|
27
|
+
"quantum_admin.services.repository",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
INSTALL_HINT = 'pip install "quantum-framework[admin]"'
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def create_admin_parser(subparsers):
|
|
34
|
+
parser = subparsers.add_parser('admin', help='Start the Quantum Admin')
|
|
35
|
+
parser.add_argument('--port', type=int, default=8090, help='Port (default 8090)')
|
|
36
|
+
parser.add_argument('--data', default='.quantum-admin',
|
|
37
|
+
help='Folder for the admin database and settings (default ./.quantum-admin)')
|
|
38
|
+
parser.add_argument('--root', default='.',
|
|
39
|
+
help='Folder the project paths are relative to (default: current folder)')
|
|
40
|
+
return parser
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def missing_dependencies():
|
|
44
|
+
"""Names of the [admin] extra's packages that do not import."""
|
|
45
|
+
faltando = []
|
|
46
|
+
for modulo, pacote in (("sqlalchemy", "SQLAlchemy"), ("jwt", "PyJWT"),
|
|
47
|
+
("cryptography", "cryptography")):
|
|
48
|
+
try:
|
|
49
|
+
__import__(modulo)
|
|
50
|
+
except ImportError:
|
|
51
|
+
faltando.append(pacote)
|
|
52
|
+
return faltando
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def _package() -> Path:
|
|
56
|
+
import quantum_admin
|
|
57
|
+
return Path(quantum_admin.__file__).resolve().parent
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def screens_folder() -> Path:
|
|
61
|
+
return _package() / "components"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def assets_folder() -> Path:
|
|
65
|
+
"""The screens' CSS and JS, served under /static/."""
|
|
66
|
+
return _package() / "assets"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _secret(arquivo: Path) -> str:
|
|
70
|
+
"""A key kept in the data folder, so sessions survive a restart."""
|
|
71
|
+
if arquivo.exists():
|
|
72
|
+
return arquivo.read_text(encoding="utf-8").strip()
|
|
73
|
+
chave = secrets.token_hex(32)
|
|
74
|
+
arquivo.write_text(chave, encoding="utf-8")
|
|
75
|
+
try:
|
|
76
|
+
arquivo.chmod(0o600)
|
|
77
|
+
except OSError:
|
|
78
|
+
pass
|
|
79
|
+
return chave
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def prepare(data: str, root: str, port: int) -> Path:
|
|
83
|
+
"""Create the data folder, point the admin at it, write the config. Returns its path."""
|
|
84
|
+
import yaml
|
|
85
|
+
|
|
86
|
+
pasta = Path(data).resolve()
|
|
87
|
+
(pasta / "settings").mkdir(parents=True, exist_ok=True)
|
|
88
|
+
|
|
89
|
+
# Read by quantum_admin.backend at import time, so set before any import.
|
|
90
|
+
os.environ["QUANTUM_ADMIN_DATABASE_URL"] = f"sqlite:///{(pasta / 'quantum_admin.db').as_posix()}"
|
|
91
|
+
os.environ["QUANTUM_ADMIN_SETTINGS_DIR"] = str(pasta / "settings")
|
|
92
|
+
os.environ["QUANTUM_ADMIN_ROOT"] = str(Path(root).resolve())
|
|
93
|
+
os.environ.setdefault("JWT_SECRET_KEY", _secret(pasta / "jwt_secret"))
|
|
94
|
+
|
|
95
|
+
config = pasta / "quantum.config.yaml"
|
|
96
|
+
config.write_text(
|
|
97
|
+
"# Generated by `quantum admin` on every start; edits are overwritten.\n" +
|
|
98
|
+
yaml.safe_dump({
|
|
99
|
+
"server": {"host": "127.0.0.1", "port": port, "reload": False, "debug": False},
|
|
100
|
+
"paths": {"components": screens_folder().as_posix(),
|
|
101
|
+
"static": assets_folder().as_posix(),
|
|
102
|
+
"uploads": (pasta / "uploads").as_posix(),
|
|
103
|
+
"logs": (pasta / "logs").as_posix()},
|
|
104
|
+
"security": {"login_url": "/admin/login", "secret_key": _secret(pasta / "session_secret")},
|
|
105
|
+
"logging": {"level": "WARNING", "console": True, "file": False},
|
|
106
|
+
"services": MODULES,
|
|
107
|
+
}, sort_keys=False),
|
|
108
|
+
encoding="utf-8")
|
|
109
|
+
return config
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def handle_admin(args) -> int:
|
|
113
|
+
faltando = missing_dependencies()
|
|
114
|
+
if faltando:
|
|
115
|
+
print(f"[ERROR] The admin needs {', '.join(faltando)}. Install with:\n {INSTALL_HINT}")
|
|
116
|
+
return 1
|
|
117
|
+
|
|
118
|
+
config = prepare(args.data, args.root, args.port)
|
|
119
|
+
|
|
120
|
+
from quantum.runtime.web_server import QuantumWebServer
|
|
121
|
+
from quantum_admin.backend.auth_service import get_auth_service
|
|
122
|
+
|
|
123
|
+
# Created now, not at the first login, so a generated password is printed
|
|
124
|
+
# before the URL instead of in the middle of the request log.
|
|
125
|
+
get_auth_service()
|
|
126
|
+
print(f"\n Quantum Admin: http://127.0.0.1:{args.port}/admin"
|
|
127
|
+
f"\n data: {config.parent}\n")
|
|
128
|
+
|
|
129
|
+
server = QuantumWebServer(str(config))
|
|
130
|
+
server.PID_FILE = str(config.parent / "admin.pid")
|
|
131
|
+
return server.start() or 0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""
|
|
2
2
|
Quantum CLI - Database Migration Commands
|
|
3
|
-
|
|
3
|
+
Applies migrations to a datasource declared in quantum.config.yaml (DB-6)
|
|
4
4
|
"""
|
|
5
5
|
import os
|
|
6
6
|
import sys
|
|
@@ -44,95 +44,76 @@ class Migration:
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class DatabaseConnection:
|
|
47
|
-
"""
|
|
47
|
+
"""Connection to the datasource the migrations are for (DB-6).
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
It used to read a separate `database:` section that nothing else uses and,
|
|
50
|
+
without one, try a PostgreSQL at localhost/quantum with user postgres before
|
|
51
|
+
falling back to ./data/quantum.db. A project whose pages query
|
|
52
|
+
datasources.db (./data/app.db) had its migrations applied to a different
|
|
53
|
+
file — or to whatever local PostgreSQL answered.
|
|
54
|
+
"""
|
|
55
|
+
|
|
56
|
+
def __init__(self, project_path: Path = None, datasource: str = None):
|
|
50
57
|
self.project_path = project_path or Path.cwd()
|
|
58
|
+
self.datasource = datasource
|
|
51
59
|
self._conn = None
|
|
52
60
|
self._db_type = None
|
|
53
61
|
|
|
54
62
|
def connect(self) -> Any:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
nome, config = self._datasource_config()
|
|
64
|
+
driver = str(config.get('driver', '')).lower()
|
|
65
|
+
if driver == 'sqlite':
|
|
66
|
+
import sqlite3
|
|
67
|
+
caminho = Path(config.get('database') or '')
|
|
68
|
+
if not config.get('database'):
|
|
69
|
+
raise MigrationError(f"datasource '{nome}' (sqlite) has no database: path")
|
|
70
|
+
if not caminho.is_absolute():
|
|
71
|
+
caminho = self.project_path / caminho
|
|
72
|
+
caminho.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
self._conn = sqlite3.connect(str(caminho))
|
|
74
|
+
self._db_type = 'sqlite'
|
|
75
|
+
logger.info("Migrating datasource %s (SQLite at %s)", nome, caminho)
|
|
64
76
|
return self._conn
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
if driver in ('postgres', 'postgresql'):
|
|
78
|
+
try:
|
|
79
|
+
import psycopg2
|
|
80
|
+
except ImportError as exc:
|
|
81
|
+
raise MigrationError("datasource '%s' is PostgreSQL: pip install psycopg2-binary" % nome) from exc
|
|
82
|
+
self._conn = psycopg2.connect(
|
|
83
|
+
host=config.get('host', 'localhost'), port=int(config.get('port', 5432)),
|
|
84
|
+
dbname=config.get('database'), user=config.get('username') or config.get('user'),
|
|
85
|
+
password=config.get('password', ''), connect_timeout=5)
|
|
86
|
+
self._db_type = 'postgres'
|
|
87
|
+
logger.info("Migrating datasource %s (PostgreSQL %s)", nome, config.get('database'))
|
|
69
88
|
return self._conn
|
|
89
|
+
raise MigrationError(f"datasource '{nome}': driver {driver!r} is not supported by quantum migrate "
|
|
90
|
+
f"(use sqlite or postgres)")
|
|
70
91
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
def _load_config(self) -> Dict:
|
|
74
|
-
"""Load database configuration from quantum.config.yaml"""
|
|
92
|
+
def _datasource_config(self):
|
|
75
93
|
config_path = self.project_path / "quantum.config.yaml"
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
try:
|
|
94
|
+
datasources = {}
|
|
95
|
+
if config_path.exists():
|
|
80
96
|
import yaml
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
self.
|
|
101
|
-
host=host,
|
|
102
|
-
port=int(port),
|
|
103
|
-
database=database,
|
|
104
|
-
user=user,
|
|
105
|
-
password=password,
|
|
106
|
-
connect_timeout=5
|
|
107
|
-
)
|
|
108
|
-
self._db_type = 'postgres'
|
|
109
|
-
logger.info(f"Connected to PostgreSQL at {host}:{port}/{database}")
|
|
110
|
-
return True
|
|
111
|
-
|
|
112
|
-
except ImportError:
|
|
113
|
-
logger.debug("psycopg2 not installed")
|
|
114
|
-
return False
|
|
115
|
-
except Exception as e:
|
|
116
|
-
logger.debug(f"PostgreSQL connection failed: {e}")
|
|
117
|
-
return False
|
|
118
|
-
|
|
119
|
-
def _try_sqlite(self, config: Dict) -> bool:
|
|
120
|
-
"""Try to connect to SQLite"""
|
|
121
|
-
try:
|
|
122
|
-
import sqlite3
|
|
123
|
-
|
|
124
|
-
db_path = config.get('sqlite_path') or self.project_path / "data" / "quantum.db"
|
|
125
|
-
db_path = Path(db_path)
|
|
126
|
-
db_path.parent.mkdir(parents=True, exist_ok=True)
|
|
127
|
-
|
|
128
|
-
self._conn = sqlite3.connect(str(db_path))
|
|
129
|
-
self._db_type = 'sqlite'
|
|
130
|
-
logger.info(f"Connected to SQLite at {db_path}")
|
|
131
|
-
return True
|
|
132
|
-
|
|
133
|
-
except Exception as e:
|
|
134
|
-
logger.error(f"SQLite connection failed: {e}")
|
|
135
|
-
return False
|
|
97
|
+
from quantum.core.config_env import expand_env
|
|
98
|
+
with open(config_path, encoding='utf-8') as f:
|
|
99
|
+
datasources = (expand_env(yaml.safe_load(f) or {}).get('datasources') or {})
|
|
100
|
+
if not datasources:
|
|
101
|
+
raise MigrationError(
|
|
102
|
+
"quantum.config.yaml declares no datasources. Add one, for example:\n"
|
|
103
|
+
" datasources:\n db:\n driver: sqlite\n database: ./data/app.db")
|
|
104
|
+
if self.datasource:
|
|
105
|
+
if self.datasource not in datasources:
|
|
106
|
+
raise MigrationError(f"no datasource '{self.datasource}'; declared: {', '.join(datasources)}")
|
|
107
|
+
return self.datasource, datasources[self.datasource]
|
|
108
|
+
if len(datasources) > 1:
|
|
109
|
+
raise MigrationError(f"several datasources are declared ({', '.join(datasources)}); "
|
|
110
|
+
f"choose one with --datasource")
|
|
111
|
+
nome = next(iter(datasources))
|
|
112
|
+
return nome, datasources[nome]
|
|
113
|
+
|
|
114
|
+
def _ensure_connected(self):
|
|
115
|
+
if self._conn is None:
|
|
116
|
+
self.connect()
|
|
136
117
|
|
|
137
118
|
@property
|
|
138
119
|
def db_type(self) -> str:
|
|
@@ -163,10 +144,10 @@ class MigrationRunner:
|
|
|
163
144
|
|
|
164
145
|
MIGRATIONS_TABLE = "_migrations"
|
|
165
146
|
|
|
166
|
-
def __init__(self, project_path: Path = None):
|
|
147
|
+
def __init__(self, project_path: Path = None, datasource: str = None):
|
|
167
148
|
self.project_path = project_path or Path.cwd()
|
|
168
149
|
self.migrations_dir = self.project_path / "migrations"
|
|
169
|
-
self.db = DatabaseConnection(self.project_path)
|
|
150
|
+
self.db = DatabaseConnection(self.project_path, datasource)
|
|
170
151
|
|
|
171
152
|
def _ensure_migrations_table(self):
|
|
172
153
|
"""Create migrations tracking table if it doesn't exist"""
|
|
@@ -25,7 +25,6 @@ from quantum.core.parser import QuantumParser, QuantumParseError
|
|
|
25
25
|
from quantum.core.ast_nodes import ComponentNode, ApplicationNode, JobNode
|
|
26
26
|
from quantum.runtime.component import ComponentRuntime, ComponentExecutionError
|
|
27
27
|
from quantum.runtime.web_server import QuantumWebServer
|
|
28
|
-
from quantum.runtime.api_server import QuantumAPIServer
|
|
29
28
|
|
|
30
29
|
# Import deploy commands (lazy load to avoid import errors if requests not installed)
|
|
31
30
|
def _get_deploy_module():
|
|
@@ -77,12 +76,15 @@ def load_config(config_path: str = 'quantum.config.yaml') -> dict:
|
|
|
77
76
|
so `datasources:` declared in quantum.config.yaml were never seen and
|
|
78
77
|
every q:query fell through to the optional Quantum Admin API.
|
|
79
78
|
"""
|
|
79
|
+
from quantum.core.config_env import ConfigEnvError, expand_env
|
|
80
80
|
try:
|
|
81
81
|
import yaml
|
|
82
82
|
path = Path(config_path)
|
|
83
83
|
if path.exists():
|
|
84
84
|
with open(path, 'r', encoding='utf-8') as fh:
|
|
85
|
-
return yaml.safe_load(fh) or {}
|
|
85
|
+
return expand_env(yaml.safe_load(fh) or {})
|
|
86
|
+
except ConfigEnvError:
|
|
87
|
+
raise # CFG-1: never run with a half-read config
|
|
86
88
|
except Exception as exc:
|
|
87
89
|
print(f"[WARN] Could not read {config_path}: {exc}")
|
|
88
90
|
return {}
|
|
@@ -187,10 +189,6 @@ class QuantumRunner:
|
|
|
187
189
|
elif app.app_type == 'ui':
|
|
188
190
|
target = getattr(self, '_ui_target', 'html')
|
|
189
191
|
return self._build_ui(app, target, debug)
|
|
190
|
-
elif app.app_type == 'html':
|
|
191
|
-
return self._start_web_server(app)
|
|
192
|
-
elif app.app_type in ('microservices', 'api'):
|
|
193
|
-
return self._start_api_server(app)
|
|
194
192
|
else:
|
|
195
193
|
print(f"[ERROR] Application type '{app.app_type}' not supported")
|
|
196
194
|
return 1
|
|
@@ -271,32 +269,6 @@ class QuantumRunner:
|
|
|
271
269
|
# TODO: Implement real job execution
|
|
272
270
|
print("[SUCCESS] Job executed successfully")
|
|
273
271
|
return 0
|
|
274
|
-
|
|
275
|
-
def _start_web_server(self, app: ApplicationNode) -> int:
|
|
276
|
-
"""Start web server"""
|
|
277
|
-
try:
|
|
278
|
-
server = QuantumWebServer(port=8080)
|
|
279
|
-
server.configure_from_ast(app)
|
|
280
|
-
# Propagate the server's exit code: it returns non-zero when the
|
|
281
|
-
# port is taken or the bind fails, and swallowing that made
|
|
282
|
-
# `quantum run` report success with nothing listening.
|
|
283
|
-
return server.start() or 0
|
|
284
|
-
except Exception as e:
|
|
285
|
-
print(f"[ERROR] Web server error: {e}")
|
|
286
|
-
return 1
|
|
287
|
-
|
|
288
|
-
def _start_api_server(self, app: ApplicationNode) -> int:
|
|
289
|
-
"""Start API server"""
|
|
290
|
-
try:
|
|
291
|
-
server = QuantumAPIServer(port=8080)
|
|
292
|
-
server.configure_from_ast(app)
|
|
293
|
-
# Propagate the server's exit code: it returns non-zero when the
|
|
294
|
-
# port is taken or the bind fails, and swallowing that made
|
|
295
|
-
# `quantum run` report success with nothing listening.
|
|
296
|
-
return server.start() or 0
|
|
297
|
-
except Exception as e:
|
|
298
|
-
print(f"[ERROR] API server error: {e}")
|
|
299
|
-
return 1
|
|
300
272
|
|
|
301
273
|
|
|
302
274
|
def main():
|
|
@@ -308,8 +280,7 @@ def main():
|
|
|
308
280
|
Examples:
|
|
309
281
|
quantum start # Start web server (magic!)
|
|
310
282
|
quantum run hello.q # Execute component
|
|
311
|
-
quantum
|
|
312
|
-
quantum run api.q # Start API server
|
|
283
|
+
quantum admin # Start the Quantum Admin
|
|
313
284
|
quantum run game.q --engine godot # Build Godot 4 project
|
|
314
285
|
quantum run backup-job.q # Execute job
|
|
315
286
|
quantum deploy ./my-app # Deploy application
|
|
@@ -360,6 +331,10 @@ Examples:
|
|
|
360
331
|
# Stop command
|
|
361
332
|
subparsers.add_parser('stop', help='Stop running web server')
|
|
362
333
|
|
|
334
|
+
# Admin command (the screens need the [admin] extra; checked when run)
|
|
335
|
+
from quantum.cli.admin import create_admin_parser
|
|
336
|
+
create_admin_parser(subparsers)
|
|
337
|
+
|
|
363
338
|
# Deploy commands (if available)
|
|
364
339
|
deploy_available, create_deploy_parser, create_apps_parser, handle_deploy, handle_apps = _get_deploy_module()
|
|
365
340
|
|
|
@@ -387,6 +362,7 @@ Examples:
|
|
|
387
362
|
|
|
388
363
|
# Migration commands
|
|
389
364
|
migrate_parser = subparsers.add_parser('migrate', help='Database migration commands')
|
|
365
|
+
migrate_parser.add_argument('--datasource', help='Datasource from quantum.config.yaml (default: the only one declared)')
|
|
390
366
|
migrate_subparsers = migrate_parser.add_subparsers(dest='migrate_command')
|
|
391
367
|
|
|
392
368
|
migrate_subparsers.add_parser('status', help='Show migration status')
|
|
@@ -421,6 +397,10 @@ Examples:
|
|
|
421
397
|
traceback.print_exc()
|
|
422
398
|
sys.exit(1)
|
|
423
399
|
|
|
400
|
+
elif args.command == 'admin':
|
|
401
|
+
from quantum.cli.admin import handle_admin
|
|
402
|
+
sys.exit(handle_admin(args))
|
|
403
|
+
|
|
424
404
|
# Handle 'stop' command
|
|
425
405
|
elif args.command == 'stop':
|
|
426
406
|
from quantum.cli.server_process import stop_server
|
|
@@ -491,7 +471,7 @@ Examples:
|
|
|
491
471
|
MigrationRunner = result
|
|
492
472
|
|
|
493
473
|
try:
|
|
494
|
-
runner = MigrationRunner()
|
|
474
|
+
runner = MigrationRunner(datasource=getattr(args, 'datasource', None))
|
|
495
475
|
|
|
496
476
|
if args.migrate_command == 'status':
|
|
497
477
|
import json
|
|
@@ -112,6 +112,7 @@ class ComponentNode(QuantumNode):
|
|
|
112
112
|
# Phase G: Authentication & Security
|
|
113
113
|
self.require_auth = False # Require authentication to access component
|
|
114
114
|
self.require_role = None # Required role(s) to access (comma-separated: "admin,editor")
|
|
115
|
+
self.login_url = None # AUTH-4: overrides security.login_url for this component
|
|
115
116
|
self.require_permission = None # Required permission(s)
|
|
116
117
|
|
|
117
118
|
# HTML rendering & interactivity (Phase 1 & future Phase 3)
|
|
@@ -1919,6 +1920,7 @@ class DataNode(QuantumNode):
|
|
|
1919
1920
|
|
|
1920
1921
|
# Result metadata
|
|
1921
1922
|
self.result: Optional[str] = None
|
|
1923
|
+
self.on_error: str = 'fail' # DATA-4: 'fail' or 'continue'
|
|
1922
1924
|
|
|
1923
1925
|
# Child elements
|
|
1924
1926
|
self.columns: List[ColumnNode] = []
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""
|
|
2
|
+
`${VAR}` in quantum.config.yaml (CFG-1).
|
|
3
|
+
|
|
4
|
+
datasources:
|
|
5
|
+
db:
|
|
6
|
+
password: ${DB_PASSWORD}
|
|
7
|
+
host: ${DB_HOST:-localhost}
|
|
8
|
+
port: ${DB_PORT:5432} # ':' works as well as ':-'
|
|
9
|
+
|
|
10
|
+
A config file is the place people put secrets by reference, and every loader
|
|
11
|
+
used to read `${DB_PASSWORD}` as the literal password. There were four loaders
|
|
12
|
+
(the CLI, the web server, the service container, migrations); they all go
|
|
13
|
+
through expand_env now.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import os
|
|
17
|
+
import re
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
_REFERENCE = re.compile(r'\$\$|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::-?([^}]*))?\}')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ConfigEnvError(ValueError):
|
|
24
|
+
"""A `${VAR}` with no value and no default."""
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def expand_env(value: Any, path: str = '') -> Any:
|
|
28
|
+
"""Replace `${NAME}` and `${NAME:-default}` in every string of a loaded config.
|
|
29
|
+
|
|
30
|
+
`$$` is a literal `$`. A variable that is not set and has no default is an
|
|
31
|
+
error naming the variable and where it was used — an empty password or
|
|
32
|
+
database path would otherwise fail much later, somewhere else.
|
|
33
|
+
"""
|
|
34
|
+
if isinstance(value, dict):
|
|
35
|
+
return {k: expand_env(v, f'{path}.{k}' if path else str(k)) for k, v in value.items()}
|
|
36
|
+
if isinstance(value, list):
|
|
37
|
+
return [expand_env(v, f'{path}[{i}]') for i, v in enumerate(value)]
|
|
38
|
+
if not isinstance(value, str) or '$' not in value:
|
|
39
|
+
return value
|
|
40
|
+
|
|
41
|
+
def substitute(match):
|
|
42
|
+
if match.group(0) == '$$':
|
|
43
|
+
return '$'
|
|
44
|
+
name, default = match.group(1), match.group(2)
|
|
45
|
+
if name in os.environ:
|
|
46
|
+
return os.environ[name]
|
|
47
|
+
if default is not None:
|
|
48
|
+
return default
|
|
49
|
+
raise ConfigEnvError(
|
|
50
|
+
f"quantum.config.yaml: {path or 'value'} uses ${{{name}}}, but the "
|
|
51
|
+
f"environment variable {name} is not set. Set it, or give a default: "
|
|
52
|
+
f"${{{name}:-value}}")
|
|
53
|
+
|
|
54
|
+
return _REFERENCE.sub(substitute, value)
|