quantum-framework 0.20.0__tar.gz → 0.22.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.20.0/quantum_framework.egg-info → quantum_framework-0.22.0}/PKG-INFO +11 -7
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/README.md +11 -7
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/pyproject.toml +15 -9
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/admin.py +26 -26
- quantum_framework-0.22.0/quantum/cli/check.py +236 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/deploy.py +51 -51
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/hot_reload.py +1 -1
- quantum_framework-0.20.0/quantum/cli/commands/migrate.py → quantum_framework-0.22.0/quantum/cli/migrations.py +33 -138
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/runner.py +17 -25
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/schema_plan.py +1 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/server_process.py +52 -52
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/ast_nodes.py +10 -44
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/expression_stdlib.py +7 -7
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/expressions.py +90 -84
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/agents/src/ast_node.py +2 -5
- quantum_framework-0.22.0/quantum/core/features/native_testing/src/__init__.py +4 -0
- quantum_framework-0.22.0/quantum/core/features/native_testing/src/ast_node.py +42 -0
- quantum_framework-0.22.0/quantum/core/features/native_testing/src/parser.py +205 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/state_management/src/ast_node.py +11 -11
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/ui_engine/src/ast_nodes.py +16 -7
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/ui_engine/src/parser.py +27 -21
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/guards.py +14 -14
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/html_compat.py +59 -59
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parser.py +201 -229
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/ai/agent_parser.py +2 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/ai/llm_parser.py +10 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/base.py +28 -28
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/control_flow/if_parser.py +5 -5
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/data/query_parser.py +40 -34
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/data/transaction_parser.py +18 -6
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/forms/action_parser.py +5 -5
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/functions/param_parser.py +13 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/services/file_parser.py +4 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/services/mail_parser.py +5 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/tiers.py +45 -19
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/xml_lines.py +15 -15
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/action_handler.py +56 -50
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/adapters/sqlite_adapter.py +31 -31
- quantum_framework-0.22.0/quantum/runtime/app_testing.py +686 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/component.py +59 -88
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/component_composer.py +34 -34
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/database_service.py +11 -11
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/db_schema.py +22 -22
- quantum_framework-0.22.0/quantum/runtime/dev_panel.py +178 -0
- quantum_framework-0.22.0/quantum/runtime/email_service.py +158 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/ai/agent_executor.py +1 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/ai/llm_executor.py +21 -8
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/ai/team_executor.py +1 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/base.py +4 -4
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/control_flow/loop_executor.py +25 -21
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/control_flow/set_executor.py +26 -26
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/data/data_executor.py +2 -2
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/data/invoke_executor.py +9 -9
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/data/query_executor.py +13 -13
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/data/transaction_executor.py +3 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/services/file_executor.py +32 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/services/mail_executor.py +10 -6
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/file_upload_service.py +2 -2
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/function_registry.py +3 -3
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/knowledge_service.py +2 -92
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/local_server.py +4 -4
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/message_queue_service.py +26 -26
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/param_validation.py +64 -45
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/renderer.py +52 -51
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/service_container.py +33 -11
- quantum_framework-0.22.0/quantum/runtime/table_params.py +163 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/terminal_code_generator.py +20 -20
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/terminal_templates.py +15 -15
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_builder.py +19 -19
- quantum_framework-0.22.0/quantum/runtime/ui_console.py +447 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_desktop.py +7 -7
- quantum_framework-0.22.0/quantum/runtime/ui_form_rules.py +217 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_html_adapter.py +64 -49
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_html_templates.py +28 -28
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_page_renderer.py +162 -139
- quantum_framework-0.22.0/quantum/runtime/ui_pager.py +73 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_table_edit.py +52 -52
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_textual_adapter.py +55 -55
- quantum_framework-0.22.0/quantum/runtime/ui_view.py +238 -0
- quantum_framework-0.22.0/quantum/runtime/web_config.py +238 -0
- quantum_framework-0.22.0/quantum/runtime/web_errors.py +243 -0
- quantum_framework-0.22.0/quantum/runtime/web_html.py +605 -0
- quantum_framework-0.22.0/quantum/runtime/web_lifecycle.py +178 -0
- quantum_framework-0.22.0/quantum/runtime/web_server.py +946 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/websocket_service.py +32 -32
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/websocket_transport.py +41 -39
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/services.py +3 -3
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/_layout/AdminShell.q +5 -5
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/agents.q +25 -25
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/app/[name].q +86 -86
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/applications.q +27 -27
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/component/[...path].q +27 -27
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/components.q +8 -8
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/connectors.q +66 -66
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/dashboard.q +6 -6
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/database.q +22 -22
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/features.q +9 -9
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/index.q +1 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/jobs.q +12 -12
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/login.q +3 -3
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/logout.q +1 -1
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/settings.q +21 -21
- quantum_framework-0.22.0/quantum_admin/components/admin/source.q +45 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/components/admin/tests.q +9 -9
- quantum_framework-0.22.0/quantum_admin/core/__init__.py +6 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/connector_service.py +3 -3
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/crud.py +58 -58
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/secret_manager.py +25 -24
- quantum_framework-0.22.0/quantum_admin/services/__init__.py +16 -0
- quantum_framework-0.22.0/quantum_admin/services/_base.py +84 -0
- quantum_framework-0.22.0/quantum_admin/services/_yaml_editor.py +82 -0
- quantum_framework-0.22.0/quantum_admin/services/apps.py +330 -0
- quantum_framework-0.22.0/quantum_admin/services/auth.py +61 -0
- quantum_framework-0.22.0/quantum_admin/services/components.py +210 -0
- quantum_framework-0.22.0/quantum_admin/services/connectors.py +165 -0
- quantum_framework-0.22.0/quantum_admin/services/projects.py +189 -0
- quantum_framework-0.22.0/quantum_admin/services/repository.py +223 -0
- quantum_framework-0.22.0/quantum_admin/services/settings.py +150 -0
- quantum_framework-0.22.0/quantum_admin/services/yaml_import.py +118 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0/quantum_framework.egg-info}/PKG-INFO +11 -7
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_framework.egg-info/SOURCES.txt +19 -48
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_message_broker.py +12 -12
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_message_queue.py +44 -43
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_pypy_compat.py +3 -3
- quantum_framework-0.20.0/quantum/cli/check.py +0 -223
- quantum_framework-0.20.0/quantum/cli/commands/__init__.py +0 -15
- quantum_framework-0.20.0/quantum/cli/commands/build.py +0 -414
- quantum_framework-0.20.0/quantum/cli/commands/dev.py +0 -185
- quantum_framework-0.20.0/quantum/cli/commands/docs.py +0 -329
- quantum_framework-0.20.0/quantum/cli/commands/lint.py +0 -523
- quantum_framework-0.20.0/quantum/cli/commands/new.py +0 -622
- quantum_framework-0.20.0/quantum/cli/commands/serve.py +0 -190
- quantum_framework-0.20.0/quantum/cli/commands/test.py +0 -193
- quantum_framework-0.20.0/quantum/cli/utils.py +0 -334
- quantum_framework-0.20.0/quantum/core/features/testing_engine/src/__init__.py +0 -41
- quantum_framework-0.20.0/quantum/core/features/testing_engine/src/ast_nodes.py +0 -1212
- quantum_framework-0.20.0/quantum/core/features/testing_engine/src/parser.py +0 -604
- quantum_framework-0.20.0/quantum/runtime/dev_panel.py +0 -178
- quantum_framework-0.20.0/quantum/runtime/email_service.py +0 -162
- quantum_framework-0.20.0/quantum/runtime/table_params.py +0 -163
- quantum_framework-0.20.0/quantum/runtime/testing_builder.py +0 -77
- quantum_framework-0.20.0/quantum/runtime/testing_code_generator.py +0 -833
- quantum_framework-0.20.0/quantum/runtime/testing_templates.py +0 -85
- quantum_framework-0.20.0/quantum/runtime/ui_console.py +0 -435
- quantum_framework-0.20.0/quantum/runtime/ui_form_rules.py +0 -193
- quantum_framework-0.20.0/quantum/runtime/ui_pager.py +0 -73
- quantum_framework-0.20.0/quantum/runtime/ui_view.py +0 -238
- quantum_framework-0.20.0/quantum/runtime/web_server.py +0 -2150
- quantum_framework-0.20.0/quantum_admin/backend/__init__.py +0 -4
- quantum_framework-0.20.0/quantum_admin/backend/audit_service.py +0 -346
- quantum_framework-0.20.0/quantum_admin/backend/component_discovery.py +0 -766
- quantum_framework-0.20.0/quantum_admin/backend/config_generator.py +0 -586
- quantum_framework-0.20.0/quantum_admin/backend/db_setup_service.py +0 -193
- quantum_framework-0.20.0/quantum_admin/backend/deploy_service.py +0 -698
- quantum_framework-0.20.0/quantum_admin/backend/git_service.py +0 -370
- quantum_framework-0.20.0/quantum_admin/backend/health_service.py +0 -390
- quantum_framework-0.20.0/quantum_admin/backend/job_service.py +0 -347
- quantum_framework-0.20.0/quantum_admin/backend/log_service.py +0 -331
- quantum_framework-0.20.0/quantum_admin/backend/main.py +0 -14426
- quantum_framework-0.20.0/quantum_admin/backend/pipeline_service.py +0 -812
- quantum_framework-0.20.0/quantum_admin/backend/resource_manager.py +0 -1118
- quantum_framework-0.20.0/quantum_admin/backend/schemas.py +0 -419
- quantum_framework-0.20.0/quantum_admin/backend/template_service.py +0 -710
- quantum_framework-0.20.0/quantum_admin/backend/test_execution_service.py +0 -364
- quantum_framework-0.20.0/quantum_admin/backend/test_generator.py +0 -782
- quantum_framework-0.20.0/quantum_admin/backend/webhook_service.py +0 -454
- quantum_framework-0.20.0/quantum_admin/backend/websocket_manager.py +0 -360
- quantum_framework-0.20.0/quantum_admin/components/admin/source.q +0 -45
- quantum_framework-0.20.0/quantum_admin/run.py +0 -13
- quantum_framework-0.20.0/quantum_admin/services/__init__.py +0 -16
- quantum_framework-0.20.0/quantum_admin/services/_base.py +0 -84
- quantum_framework-0.20.0/quantum_admin/services/_yaml_editor.py +0 -82
- quantum_framework-0.20.0/quantum_admin/services/apps.py +0 -330
- quantum_framework-0.20.0/quantum_admin/services/auth.py +0 -61
- quantum_framework-0.20.0/quantum_admin/services/components.py +0 -210
- quantum_framework-0.20.0/quantum_admin/services/connectors.py +0 -164
- quantum_framework-0.20.0/quantum_admin/services/projects.py +0 -189
- quantum_framework-0.20.0/quantum_admin/services/repository.py +0 -223
- quantum_framework-0.20.0/quantum_admin/services/settings.py +0 -150
- quantum_framework-0.20.0/quantum_admin/services/yaml_import.py +0 -118
- quantum_framework-0.20.0/tests/test_cli_commands.py +0 -466
- quantum_framework-0.20.0/tests/test_testing_codegen.py +0 -787
- quantum_framework-0.20.0/tests/test_testing_parser.py +0 -671
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/LICENSE +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/jobs.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/mq.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/cli/pkg.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/base_generator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/cli.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/expression_transformer.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/javascript/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/javascript/generator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/optimizer.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/python/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/python/generator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/python/runtime.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/compiler/transpiler.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/config_env.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/docs_links.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/expression_diagnostics.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/agents/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/data_import/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/data_import/src/runtime.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/dump/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/dump/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/dump/src/parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/dump/src/runtime.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/functions/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/functions/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/invocation/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/invocation/src/runtime.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/logging/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/logging/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/logging/src/parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/logging/src/runtime.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/loops/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/loops/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/query/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/query/src/query_validators.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/state_management/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/theming/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/theming/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/theming/src/presets.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/websocket/src/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parser_registry.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/ai/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/ai/team_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/composition/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/composition/import_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/control_flow/set_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/data/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/data/data_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/data/invoke_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/events/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/forms/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/functions/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/functions/function_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/functions/return_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/html/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/html/html_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/jobs/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/messaging/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/routing/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/routing/route_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/scripting/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/services/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/services/dump_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/core/parsers/services/log_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/packages/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/packages/manager.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/packages/manifest.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/packages/registry.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/packages/resolver.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/plugins/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/plugins/hooks.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/plugins/loader.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/plugins/manifest.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/plugins/registry.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/adapters/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/agent_service.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ast_cache.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/auth_service.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/component_resolver.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/conditions.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/error_handler.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/execution_context.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executor_registry.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/ai/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/control_flow/if_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/control_flow/redirect_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/data/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/services/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/executors/services/log_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/expression_cache.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/game_builder.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/game_code_generator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/game_templates.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/godot_code_generator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/godot_templates.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/history.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/job_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/llm_cache.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/llm_providers.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/llm_service.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/llm_stream.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/logging_setup.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/message_broker.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/pypy_compat.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/python_bridge.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/query_validators.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/terminal_builder.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_mobile_templates.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_textual_templates.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_tokens.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/ui_validator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/validators.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/websocket_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/runtime/wsgi.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum/utils/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/__init__.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/assets/quantum-admin.css +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/auth_service.py +0 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/database.py +0 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/docker_service.py +0 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/environment_service.py +0 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/models.py +0 -0
- {quantum_framework-0.20.0/quantum_admin/backend → quantum_framework-0.22.0/quantum_admin/core}/settings_service.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_admin/services/_component_test_generator.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_framework.egg-info/entry_points.txt +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_framework.egg-info/requires.txt +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/quantum_framework.egg-info/top_level.txt +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/setup.cfg +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_agent.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_animations.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_ast_cache.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_component_library.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_expression_cache.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_form_validation.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_game_codegen.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_game_e2e.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_game_engine.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_game_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_godot_codegen.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_job_executor.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_llm_providers.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_mobile_target.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_multi_agent.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_packages.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_plugins.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_python_scripting.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_terminal_codegen.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_terminal_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_theming.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_ui_html_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_ui_parity.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_ui_parser.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.0}/tests/test_ui_textual_adapter.py +0 -0
- {quantum_framework-0.20.0 → quantum_framework-0.22.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.22.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
|
|
@@ -79,17 +79,21 @@ Retrieval-augmented generation, as a language construct:
|
|
|
79
79
|
<q:source type="directory" path="./docs/" pattern="*.md" />
|
|
80
80
|
</q:knowledge>
|
|
81
81
|
|
|
82
|
-
<q:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
</q:query>
|
|
82
|
+
<q:llm name="answer" model="phi3" knowledge="docs" minRelevance="0.79">
|
|
83
|
+
<q:message role="user">{form.question}</q:message>
|
|
84
|
+
</q:llm>
|
|
86
85
|
|
|
87
|
-
<p>{answer
|
|
86
|
+
<p>{answer}</p>
|
|
87
|
+
<q:loop type="array" items="{answer_result.sources}" var="s">
|
|
88
|
+
<p>[{s.n}] {s.name}</p>
|
|
89
|
+
</q:loop>
|
|
88
90
|
</q:component>
|
|
89
91
|
```
|
|
90
92
|
|
|
91
93
|
That indexes a directory, embeds it, stores the vectors, retrieves the relevant chunks
|
|
92
|
-
and asks the model — in the markup.
|
|
94
|
+
and asks the model to answer from them, citing each one — in the markup. When no
|
|
95
|
+
chunk is relevant enough, the model is not asked at all. There is no Python file
|
|
96
|
+
behind it.
|
|
93
97
|
|
|
94
98
|
An agent with its own tools, same idea:
|
|
95
99
|
|
|
@@ -29,17 +29,21 @@ Retrieval-augmented generation, as a language construct:
|
|
|
29
29
|
<q:source type="directory" path="./docs/" pattern="*.md" />
|
|
30
30
|
</q:knowledge>
|
|
31
31
|
|
|
32
|
-
<q:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
<
|
|
32
|
+
<q:llm name="answer" model="phi3" knowledge="docs" minRelevance="0.79">
|
|
33
|
+
<q:message role="user">{form.question}</q:message>
|
|
34
|
+
</q:llm>
|
|
35
|
+
|
|
36
|
+
<p>{answer}</p>
|
|
37
|
+
<q:loop type="array" items="{answer_result.sources}" var="s">
|
|
38
|
+
<p>[{s.n}] {s.name}</p>
|
|
39
|
+
</q:loop>
|
|
38
40
|
</q:component>
|
|
39
41
|
```
|
|
40
42
|
|
|
41
43
|
That indexes a directory, embeds it, stores the vectors, retrieves the relevant chunks
|
|
42
|
-
and asks the model — in the markup.
|
|
44
|
+
and asks the model to answer from them, citing each one — in the markup. When no
|
|
45
|
+
chunk is relevant enough, the model is not asked at all. There is no Python file
|
|
46
|
+
behind it.
|
|
43
47
|
|
|
44
48
|
An agent with its own tools, same idea:
|
|
45
49
|
|
|
@@ -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.22.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"}
|
|
@@ -78,20 +78,26 @@ Changelog = "https://github.com/danielgregorio/quantum/releases"
|
|
|
78
78
|
Repository = "https://github.com/danielgregorio/quantum"
|
|
79
79
|
|
|
80
80
|
[tool.setuptools.packages.find]
|
|
81
|
-
#
|
|
82
|
-
#
|
|
83
|
-
#
|
|
84
|
-
#
|
|
85
|
-
#
|
|
81
|
+
# Only the `quantum` package and its subpackages. The old glob `quantum*` also
|
|
82
|
+
# swept in `quantum_admin` (a separate FastAPI app, with deps of its own that
|
|
83
|
+
# are not the core's), and the `quantum-as4`/`quantum-lsp` folders (sibling
|
|
84
|
+
# projects, hyphenated and not even importable) — 91 files of dead weight in
|
|
85
|
+
# the wheel. The dot in `quantum.*` matches subpackages; without it,
|
|
86
|
+
# `quantum_admin` does not get in.
|
|
86
87
|
include = ["quantum", "quantum.*",
|
|
87
88
|
# The admin (`quantum admin`, extra [admin]): its screens, its
|
|
88
|
-
# services and the
|
|
89
|
-
# FastAPI
|
|
90
|
-
"quantum_admin", "quantum_admin.services", "quantum_admin.
|
|
89
|
+
# services and the library they use (quantum_admin.core). The old
|
|
90
|
+
# FastAPI backend (quantum_admin/backend) is not shipped (A4.2).
|
|
91
|
+
"quantum_admin", "quantum_admin.services", "quantum_admin.core"]
|
|
91
92
|
|
|
92
93
|
[tool.setuptools.package-data]
|
|
93
94
|
quantum_admin = ["components/**/*.q", "assets/*"]
|
|
94
95
|
|
|
96
|
+
[tool.setuptools.exclude-package-data]
|
|
97
|
+
# Without this, setuptools ships every folder under quantum_admin as "data".
|
|
98
|
+
quantum_admin = ["backend/*", "backend/**/*", "templates/**/*", "static/**/*", "projects/**/*",
|
|
99
|
+
"settings/**/*", "*.db"]
|
|
100
|
+
|
|
95
101
|
|
|
96
102
|
[tool.black]
|
|
97
103
|
line-length = 100
|
|
@@ -42,14 +42,14 @@ def create_admin_parser(subparsers):
|
|
|
42
42
|
|
|
43
43
|
def missing_dependencies():
|
|
44
44
|
"""Names of the [admin] extra's packages that do not import."""
|
|
45
|
-
|
|
46
|
-
for
|
|
45
|
+
missing = []
|
|
46
|
+
for module, package in (("sqlalchemy", "SQLAlchemy"), ("jwt", "PyJWT"),
|
|
47
47
|
("cryptography", "cryptography")):
|
|
48
48
|
try:
|
|
49
|
-
__import__(
|
|
49
|
+
__import__(module)
|
|
50
50
|
except ImportError:
|
|
51
|
-
|
|
52
|
-
return
|
|
51
|
+
missing.append(package)
|
|
52
|
+
return missing
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
def _package() -> Path:
|
|
@@ -66,42 +66,42 @@ def assets_folder() -> Path:
|
|
|
66
66
|
return _package() / "assets"
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
def _secret(
|
|
69
|
+
def _secret(file: Path) -> str:
|
|
70
70
|
"""A key kept in the data folder, so sessions survive a restart."""
|
|
71
|
-
if
|
|
72
|
-
return
|
|
73
|
-
|
|
74
|
-
|
|
71
|
+
if file.exists():
|
|
72
|
+
return file.read_text(encoding="utf-8").strip()
|
|
73
|
+
key = secrets.token_hex(32)
|
|
74
|
+
file.write_text(key, encoding="utf-8")
|
|
75
75
|
try:
|
|
76
|
-
|
|
76
|
+
file.chmod(0o600)
|
|
77
77
|
except OSError:
|
|
78
78
|
pass
|
|
79
|
-
return
|
|
79
|
+
return key
|
|
80
80
|
|
|
81
81
|
|
|
82
82
|
def prepare(data: str, root: str, port: int) -> Path:
|
|
83
83
|
"""Create the data folder, point the admin at it, write the config. Returns its path."""
|
|
84
84
|
import yaml
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
(
|
|
86
|
+
folder = Path(data).resolve()
|
|
87
|
+
(folder / "settings").mkdir(parents=True, exist_ok=True)
|
|
88
88
|
|
|
89
|
-
# Read by quantum_admin.
|
|
90
|
-
os.environ["QUANTUM_ADMIN_DATABASE_URL"] = f"sqlite:///{(
|
|
91
|
-
os.environ["QUANTUM_ADMIN_SETTINGS_DIR"] = str(
|
|
89
|
+
# Read by quantum_admin.core at import time, so set before any import.
|
|
90
|
+
os.environ["QUANTUM_ADMIN_DATABASE_URL"] = f"sqlite:///{(folder / 'quantum_admin.db').as_posix()}"
|
|
91
|
+
os.environ["QUANTUM_ADMIN_SETTINGS_DIR"] = str(folder / "settings")
|
|
92
92
|
os.environ["QUANTUM_ADMIN_ROOT"] = str(Path(root).resolve())
|
|
93
|
-
os.environ.setdefault("JWT_SECRET_KEY", _secret(
|
|
93
|
+
os.environ.setdefault("JWT_SECRET_KEY", _secret(folder / "jwt_secret"))
|
|
94
94
|
|
|
95
|
-
config =
|
|
95
|
+
config = folder / "quantum.config.yaml"
|
|
96
96
|
config.write_text(
|
|
97
97
|
"# Generated by `quantum admin` on every start; edits are overwritten.\n" +
|
|
98
98
|
yaml.safe_dump({
|
|
99
99
|
"server": {"host": "127.0.0.1", "port": port, "reload": False, "debug": False},
|
|
100
100
|
"paths": {"components": screens_folder().as_posix(),
|
|
101
101
|
"static": assets_folder().as_posix(),
|
|
102
|
-
"uploads": (
|
|
103
|
-
"logs": (
|
|
104
|
-
"security": {"login_url": "/admin/login", "secret_key": _secret(
|
|
102
|
+
"uploads": (folder / "uploads").as_posix(),
|
|
103
|
+
"logs": (folder / "logs").as_posix()},
|
|
104
|
+
"security": {"login_url": "/admin/login", "secret_key": _secret(folder / "session_secret")},
|
|
105
105
|
"logging": {"level": "WARNING", "console": True, "file": False},
|
|
106
106
|
"services": MODULES,
|
|
107
107
|
}, sort_keys=False),
|
|
@@ -110,15 +110,15 @@ def prepare(data: str, root: str, port: int) -> Path:
|
|
|
110
110
|
|
|
111
111
|
|
|
112
112
|
def handle_admin(args) -> int:
|
|
113
|
-
|
|
114
|
-
if
|
|
115
|
-
print(f"[ERROR] The admin needs {', '.join(
|
|
113
|
+
missing = missing_dependencies()
|
|
114
|
+
if missing:
|
|
115
|
+
print(f"[ERROR] The admin needs {', '.join(missing)}. Install with:\n {INSTALL_HINT}")
|
|
116
116
|
return 1
|
|
117
117
|
|
|
118
118
|
config = prepare(args.data, args.root, args.port)
|
|
119
119
|
|
|
120
120
|
from quantum.runtime.web_server import QuantumWebServer
|
|
121
|
-
from quantum_admin.
|
|
121
|
+
from quantum_admin.core.auth_service import get_auth_service
|
|
122
122
|
|
|
123
123
|
# Created now, not at the first login, so a generated password is printed
|
|
124
124
|
# before the URL instead of in the middle of the request log.
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
"""`quantum check`: every page parses, every q:query compiles against the database,
|
|
2
|
+
and every `{query.field}` a page reads is a column the query returns (M8, DEV-3).
|
|
3
|
+
|
|
4
|
+
A typo in SQL or in a field name used to surface only when someone opened the
|
|
5
|
+
page — `no such column` as a 500, or, for a field, an empty cell. This reads
|
|
6
|
+
the project the way the server would and reports each problem with its file
|
|
7
|
+
and line, without running anything: a query is compiled by the database
|
|
8
|
+
(EXPLAIN) and a SELECT's columns come from running it with LIMIT 0.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import re
|
|
12
|
+
from dataclasses import dataclass
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, Iterator, List, Optional
|
|
15
|
+
|
|
16
|
+
# Fields of `<name>_result` and of a query row that are not columns.
|
|
17
|
+
_META = {'recordCount', 'columnList', 'executionTime', 'success', 'error', 'sql', 'page',
|
|
18
|
+
'totalPages', 'hasMore', 'cached', 'affectedRows', 'lastInsertId', 'data', 'length'}
|
|
19
|
+
_EXPR = re.compile(r'\{([^{}]*)\}')
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
@dataclass
|
|
23
|
+
class Problem:
|
|
24
|
+
file: str
|
|
25
|
+
line: Optional[int]
|
|
26
|
+
message: str
|
|
27
|
+
|
|
28
|
+
def __str__(self) -> str:
|
|
29
|
+
return f'{self.file}:{self.line or "?"}: {self.message}'
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _config(config_path: Path) -> dict:
|
|
33
|
+
import yaml
|
|
34
|
+
from quantum.core.config_env import expand_env
|
|
35
|
+
if not config_path.exists():
|
|
36
|
+
return {}
|
|
37
|
+
return expand_env(yaml.safe_load(config_path.read_text(encoding='utf-8')) or {})
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _children(node) -> Iterator:
|
|
41
|
+
"""The nodes inside a node, whatever the field is called."""
|
|
42
|
+
for field in ('statements', 'body', 'if_body', 'else_body', 'children', 'tools'):
|
|
43
|
+
for child in getattr(node, field, None) or []:
|
|
44
|
+
if hasattr(child, '__dict__'):
|
|
45
|
+
yield child
|
|
46
|
+
for block in getattr(node, 'elseif_blocks', None) or []:
|
|
47
|
+
body = block.get('body') if isinstance(block, dict) else getattr(block, 'body', None)
|
|
48
|
+
for child in body or []:
|
|
49
|
+
yield child
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _texts(node) -> List[str]:
|
|
53
|
+
"""The strings of a node that may hold {expressions}."""
|
|
54
|
+
texts = []
|
|
55
|
+
for field, value in vars(node).items():
|
|
56
|
+
if field.startswith('_') or field in ('sql',):
|
|
57
|
+
continue
|
|
58
|
+
if isinstance(value, str) and '{' in value:
|
|
59
|
+
texts.append(value)
|
|
60
|
+
elif isinstance(value, dict):
|
|
61
|
+
texts += [v for v in value.values() if isinstance(v, str) and '{' in v]
|
|
62
|
+
return texts
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ProjectChecker:
|
|
66
|
+
def __init__(self, project: Path, config_path: Path):
|
|
67
|
+
self.project = project
|
|
68
|
+
self.config = _config(config_path)
|
|
69
|
+
self.datasources = self.config.get('datasources') or {}
|
|
70
|
+
self._connections: Dict[str, object] = {}
|
|
71
|
+
self.problems: List[Problem] = []
|
|
72
|
+
self.notes: List[str] = []
|
|
73
|
+
self.queries_checked = 0
|
|
74
|
+
self.files = 0
|
|
75
|
+
|
|
76
|
+
# -- the database ---------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
def _connection(self, name: str):
|
|
79
|
+
from quantum.runtime.db_schema import SchemaError, connect_readonly
|
|
80
|
+
if name not in self._connections:
|
|
81
|
+
try:
|
|
82
|
+
self._connections[name] = connect_readonly(self.datasources[name], self.project)
|
|
83
|
+
except SchemaError as exc:
|
|
84
|
+
self._connections[name] = None
|
|
85
|
+
self.notes.append(f'datasource {name!r} not checked: {exc}')
|
|
86
|
+
return self._connections[name]
|
|
87
|
+
|
|
88
|
+
# -- a file ---------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
def check_file(self, path: Path) -> None:
|
|
91
|
+
from quantum.core.parser import QuantumParser
|
|
92
|
+
rel = path.relative_to(self.project).as_posix() if path.is_relative_to(self.project) else str(path)
|
|
93
|
+
self.files += 1
|
|
94
|
+
try:
|
|
95
|
+
ast = QuantumParser(use_cache=False).parse_file(str(path))
|
|
96
|
+
except Exception as exc: # a parse error is a problem like any other
|
|
97
|
+
first_line = str(exc).split('\n')[0]
|
|
98
|
+
self.problems.append(Problem(rel, getattr(exc, 'line', None), first_line))
|
|
99
|
+
return
|
|
100
|
+
columns: Dict[str, List[str]] = {}
|
|
101
|
+
self._queries(ast, rel, columns)
|
|
102
|
+
self._fields(ast, rel, columns, {name: name for name in columns}, None)
|
|
103
|
+
|
|
104
|
+
def check_test_file(self, path: Path) -> None:
|
|
105
|
+
"""A *.test.q next to the pages: it parses as a test suite (TEST-4), not as a page."""
|
|
106
|
+
from quantum.core.features.native_testing.src import TestParseError, parse_test_file
|
|
107
|
+
rel = path.relative_to(self.project).as_posix() if path.is_relative_to(self.project) else str(path)
|
|
108
|
+
self.files += 1
|
|
109
|
+
try:
|
|
110
|
+
parse_test_file(path)
|
|
111
|
+
except TestParseError as exc:
|
|
112
|
+
self.problems.append(Problem(rel, exc.line, str(exc).split('\n')[0]))
|
|
113
|
+
|
|
114
|
+
def _queries(self, node, rel: str, columns: Dict[str, List[str]]) -> None:
|
|
115
|
+
from quantum.core.ast_nodes import ActionNode, QueryNode
|
|
116
|
+
from quantum.runtime.db_schema import check_sql, read_schema
|
|
117
|
+
for child in _children(node):
|
|
118
|
+
if isinstance(child, ActionNode) and getattr(child, 'table', None):
|
|
119
|
+
# UI-10: the table the action takes its params from exists, with those columns.
|
|
120
|
+
ds = child.table_datasource
|
|
121
|
+
if ds not in self.datasources:
|
|
122
|
+
self.problems.append(Problem(rel, getattr(child, 'source_line', None),
|
|
123
|
+
f'<q:action name="{child.name}">: datasource {ds!r} is not '
|
|
124
|
+
f'declared in quantum.config.yaml'))
|
|
125
|
+
elif self._connection(ds) is not None:
|
|
126
|
+
schema = read_schema(self._connection(ds))
|
|
127
|
+
table = schema.get(child.table)
|
|
128
|
+
if table is None:
|
|
129
|
+
self.problems.append(Problem(rel, getattr(child, 'source_line', None),
|
|
130
|
+
f'<q:action name="{child.name}" table="{child.table}">: '
|
|
131
|
+
f'no such table (tables: {", ".join(schema) or "none"})'))
|
|
132
|
+
else:
|
|
133
|
+
for column in child.table_columns or []:
|
|
134
|
+
if column not in table.columns:
|
|
135
|
+
self.problems.append(Problem(
|
|
136
|
+
rel, getattr(child, 'source_line', None),
|
|
137
|
+
f'<q:action name="{child.name}" columns=...>: table "{child.table}" '
|
|
138
|
+
f'has no column "{column}"'))
|
|
139
|
+
if isinstance(child, QueryNode):
|
|
140
|
+
ds = child.datasource
|
|
141
|
+
if not ds or ds.startswith('knowledge:') or getattr(child, 'source', None):
|
|
142
|
+
pass # RAG or query of queries: not SQL on a database
|
|
143
|
+
elif ds not in self.datasources:
|
|
144
|
+
self.problems.append(Problem(rel, getattr(child, 'source_line', None),
|
|
145
|
+
f'<q:query name="{child.name}">: datasource {ds!r} is not '
|
|
146
|
+
f'declared in quantum.config.yaml'))
|
|
147
|
+
else:
|
|
148
|
+
conn = self._connection(ds)
|
|
149
|
+
if conn is not None:
|
|
150
|
+
self.queries_checked += 1
|
|
151
|
+
error, cols = check_sql(conn, child.sql or '')
|
|
152
|
+
if error:
|
|
153
|
+
self.problems.append(Problem(rel, getattr(child, 'source_line', None),
|
|
154
|
+
f'<q:query name="{child.name}">: {error}'))
|
|
155
|
+
elif cols is not None:
|
|
156
|
+
columns[child.name] = cols
|
|
157
|
+
self._queries(child, rel, columns)
|
|
158
|
+
|
|
159
|
+
def _fields(self, node, rel: str, columns: Dict[str, List[str]], bound: Dict[str, str],
|
|
160
|
+
line: Optional[int]) -> None:
|
|
161
|
+
"""Each `{var.field}` where var is a query, or a row of one, names a column it returns."""
|
|
162
|
+
from quantum.core.features.loops.src.ast_node import LoopNode
|
|
163
|
+
from quantum.core.features.ui_engine.src.ast_nodes import UIColumnNode, UIListNode, UITableNode
|
|
164
|
+
line = getattr(node, 'source_line', None) or line
|
|
165
|
+
for text in _texts(node):
|
|
166
|
+
for expr in _EXPR.findall(text):
|
|
167
|
+
for var, field in re.findall(r'(?<![\w.])(\w+)\.(\w+)', expr):
|
|
168
|
+
self._field(rel, line, columns, bound, var, field)
|
|
169
|
+
if isinstance(node, UIColumnNode) and node.key and '$table' in bound:
|
|
170
|
+
self._field(rel, line, columns, bound, '$table', node.key, f'<ui:column key="{node.key}">')
|
|
171
|
+
|
|
172
|
+
for child in _children(node):
|
|
173
|
+
inner = dict(bound)
|
|
174
|
+
source = None
|
|
175
|
+
if isinstance(child, LoopNode):
|
|
176
|
+
source = child.query_name if child.loop_type == 'query' else _single_name(child.items)
|
|
177
|
+
if source in columns:
|
|
178
|
+
inner[child.var_name] = source
|
|
179
|
+
elif isinstance(child, (UITableNode, UIListNode)):
|
|
180
|
+
source = _single_name(child.source)
|
|
181
|
+
if source in columns:
|
|
182
|
+
inner[child.as_var or ('row' if isinstance(child, UITableNode) else 'item')] = source
|
|
183
|
+
if isinstance(child, UITableNode):
|
|
184
|
+
inner['$table'] = source
|
|
185
|
+
self._fields(child, rel, columns, inner, line)
|
|
186
|
+
|
|
187
|
+
def _field(self, rel, line, columns, bound, var, field, label=None) -> None:
|
|
188
|
+
query = bound.get(var)
|
|
189
|
+
if query is None or field in _META:
|
|
190
|
+
return
|
|
191
|
+
cols = columns.get(query, [])
|
|
192
|
+
if field not in cols:
|
|
193
|
+
shown = label or f'{{{var}.{field}}}'
|
|
194
|
+
self.problems.append(Problem(
|
|
195
|
+
rel, line, f'{shown}: query "{query}" returns no column "{field}" '
|
|
196
|
+
f'(columns: {", ".join(cols) or "none"})'))
|
|
197
|
+
|
|
198
|
+
# -- the project ----------------------------------------------------------
|
|
199
|
+
|
|
200
|
+
def run(self) -> List[Problem]:
|
|
201
|
+
folder = self.project / (self.config.get('paths', {}) or {}).get('components', 'components')
|
|
202
|
+
if not folder.exists():
|
|
203
|
+
self.notes.append(f'no components folder at {folder}')
|
|
204
|
+
return self.problems
|
|
205
|
+
for path in sorted(folder.rglob('*.q')):
|
|
206
|
+
if path.name.endswith('.test.q'):
|
|
207
|
+
self.check_test_file(path) # a test suite next to its page (TEST-1)
|
|
208
|
+
continue
|
|
209
|
+
self.check_file(path)
|
|
210
|
+
for conn in self._connections.values():
|
|
211
|
+
if conn is not None:
|
|
212
|
+
conn.close()
|
|
213
|
+
return self.problems
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _single_name(expr: Optional[str]) -> Optional[str]:
|
|
217
|
+
"""`{tasks}` -> 'tasks'; anything more complex -> None."""
|
|
218
|
+
m = re.fullmatch(r'\s*\{\s*(\w+)\s*\}\s*', expr or '')
|
|
219
|
+
return m.group(1) if m else None
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def run_check(config_path: str = 'quantum.config.yaml') -> int:
|
|
223
|
+
"""`quantum check`: print each problem as file:line: message; exit 1 if there is any."""
|
|
224
|
+
path = Path(config_path).resolve()
|
|
225
|
+
checker = ProjectChecker(path.parent, path)
|
|
226
|
+
problems = checker.run()
|
|
227
|
+
for note in checker.notes:
|
|
228
|
+
print(f'[NOTE] {note}')
|
|
229
|
+
for problem in problems:
|
|
230
|
+
print(problem)
|
|
231
|
+
summary = (f'{checker.files} file(s), {checker.queries_checked} query(ies) checked against the database')
|
|
232
|
+
if problems:
|
|
233
|
+
print(f'\n{len(problems)} problem(s) — {summary}.')
|
|
234
|
+
return 1
|
|
235
|
+
print(f'OK — {summary}.')
|
|
236
|
+
return 0
|
|
@@ -43,9 +43,9 @@ class QuantumDeployer:
|
|
|
43
43
|
'.env',
|
|
44
44
|
'.env.local',
|
|
45
45
|
'.env.*.local',
|
|
46
|
-
# `.env`
|
|
47
|
-
# `.env.production`
|
|
48
|
-
#
|
|
46
|
+
# `.env` alone only matched the file with that exact name:
|
|
47
|
+
# `.env.production` and `.env.prod` went to the server along with the
|
|
48
|
+
# rest.
|
|
49
49
|
'.env.*',
|
|
50
50
|
'node_modules',
|
|
51
51
|
'.venv',
|
|
@@ -67,12 +67,12 @@ class QuantumDeployer:
|
|
|
67
67
|
self.config = self._load_config(config_path)
|
|
68
68
|
self.targets = self.config.get('deploy', {}).get('targets', {})
|
|
69
69
|
|
|
70
|
-
#
|
|
70
|
+
# What `.env.*` must NOT take along.
|
|
71
71
|
#
|
|
72
|
-
# `.env.example`
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
72
|
+
# `.env.example` is the opposite of a secret: it documents which
|
|
73
|
+
# variables the operator has to define, and it is the file one WANTS on
|
|
74
|
+
# the server. A bare `.env.*` dragged these along too — trading a leak
|
|
75
|
+
# for a silent omission is not a fix.
|
|
76
76
|
KEEP_PATTERNS = [
|
|
77
77
|
'.env.example',
|
|
78
78
|
'.env.sample',
|
|
@@ -83,26 +83,26 @@ class QuantumDeployer:
|
|
|
83
83
|
|
|
84
84
|
@classmethod
|
|
85
85
|
def _is_excluded(cls, name: str) -> bool:
|
|
86
|
-
"""
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
`*x*`, `*.ext`, `
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
.env.*.local -> `.env.production.local`
|
|
93
|
-
|
|
94
|
-
tarball,
|
|
95
|
-
test_*.py ->
|
|
96
|
-
*_test.py ->
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
`fnmatchcase`,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
86
|
+
"""Does the name match some EXCLUDE_PATTERN?
|
|
87
|
+
|
|
88
|
+
This used to be a hand-written matcher that understood only four forms:
|
|
89
|
+
`*x*`, `*.ext`, `prefix*` and exact equality. A `*` in the MIDDLE fell
|
|
90
|
+
into the last case, and three patterns in the list have one:
|
|
91
|
+
|
|
92
|
+
.env.*.local -> `.env.production.local` was PACKED AND
|
|
93
|
+
SENT to the server. A production secret in
|
|
94
|
+
the tarball, with no warning at all.
|
|
95
|
+
test_*.py -> tests went along
|
|
96
|
+
*_test.py -> ditto
|
|
97
|
+
|
|
98
|
+
None of the three matched anything, except a file literally named
|
|
99
|
+
`.env.*.local`. fnmatch understands all three forms — and the
|
|
100
|
+
others keep working the same.
|
|
101
|
+
|
|
102
|
+
`fnmatchcase`, not `fnmatch`: the latter normalizes case according to
|
|
103
|
+
the OS, so the same list would exclude different things on Windows and
|
|
104
|
+
on Linux, and a deploy made from one side would upload a different set
|
|
105
|
+
of files than from the other.
|
|
106
106
|
"""
|
|
107
107
|
if any(fnmatch.fnmatchcase(name, pattern)
|
|
108
108
|
for pattern in cls.KEEP_PATTERNS):
|
|
@@ -273,17 +273,17 @@ class QuantumDeployer:
|
|
|
273
273
|
os.close(fd)
|
|
274
274
|
tarball_path = Path(tarball_path)
|
|
275
275
|
|
|
276
|
-
def should_exclude(item: Path,
|
|
277
|
-
"""
|
|
276
|
+
def should_exclude(item: Path, root: Path) -> bool:
|
|
277
|
+
"""Is the item, or one of its directories UP TO `root`, excluded?
|
|
278
278
|
|
|
279
|
-
|
|
280
|
-
`parents`
|
|
281
|
-
`C:\\...\\venv\\
|
|
282
|
-
pattern
|
|
283
|
-
|
|
279
|
+
Only up to the root. It used to be `[item] + list(item.parents)`, and
|
|
280
|
+
`parents` climbs up to the root of the disk: an app at
|
|
281
|
+
`C:\\...\\venv\\myapp` or `~/projects/tests/app` matched a
|
|
282
|
+
pattern in a directory OUTSIDE the app, and the tarball came out
|
|
283
|
+
empty — a "successful deploy" of nothing.
|
|
284
284
|
"""
|
|
285
|
-
return any(self._is_excluded(
|
|
286
|
-
for
|
|
285
|
+
return any(self._is_excluded(part)
|
|
286
|
+
for part in item.relative_to(root).parts)
|
|
287
287
|
|
|
288
288
|
with tarfile.open(tarball_path, 'w:gz') as tar:
|
|
289
289
|
# Add app files
|
|
@@ -314,10 +314,10 @@ class QuantumDeployer:
|
|
|
314
314
|
if verbose:
|
|
315
315
|
print(f" [INFO] Including quantum runtime from {quantum_src}")
|
|
316
316
|
for item in quantum_src.rglob('*'):
|
|
317
|
-
#
|
|
318
|
-
#
|
|
319
|
-
#
|
|
320
|
-
#
|
|
317
|
+
# By the directories too: only the file's NAME used
|
|
318
|
+
# to be tested, so the runtime's `tests/` was skipped
|
|
319
|
+
# as a directory but every file inside it went
|
|
320
|
+
# along.
|
|
321
321
|
if should_exclude(item, quantum_src):
|
|
322
322
|
continue
|
|
323
323
|
if item.is_file():
|
|
@@ -442,17 +442,17 @@ class QuantumAppsManager:
|
|
|
442
442
|
response.raise_for_status()
|
|
443
443
|
return response.json().get('apps', [])
|
|
444
444
|
except requests.exceptions.ConnectionError as e:
|
|
445
|
-
#
|
|
446
|
-
#
|
|
447
|
-
#
|
|
448
|
-
#
|
|
445
|
+
# The default target is `http://forge:9000`, a host that only
|
|
446
|
+
# resolves on the network of whoever wrote this. For everyone else,
|
|
447
|
+
# `quantum apps` failed with a DNS error citing a never-seen name
|
|
448
|
+
# and without saying where it came from.
|
|
449
449
|
raise DeployError(
|
|
450
|
-
f"
|
|
451
|
-
f"
|
|
452
|
-
f"Quantum Forge,
|
|
453
|
-
f"
|
|
454
|
-
f"QUANTUM_FORGE_URL=http://
|
|
455
|
-
f"
|
|
450
|
+
f"Could not reach the deploy server at {url}.\n"
|
|
451
|
+
f" That is the target '{target}'. If you do not have a "
|
|
452
|
+
f"Quantum Forge server, this command does not apply to you.\n"
|
|
453
|
+
f" To point it somewhere else: "
|
|
454
|
+
f"QUANTUM_FORGE_URL=http://your-host:port\n"
|
|
455
|
+
f" Detail: {e}"
|
|
456
456
|
)
|
|
457
457
|
except requests.exceptions.RequestException as e:
|
|
458
458
|
raise DeployError(f"Failed to list apps: {e}")
|
|
@@ -412,7 +412,7 @@ class HotReloadManager:
|
|
|
412
412
|
ws_port: WebSocket server port
|
|
413
413
|
debounce_ms: Debounce delay in milliseconds
|
|
414
414
|
on_reload: Optional callback when reload is triggered
|
|
415
|
-
console: Optional console for logging
|
|
415
|
+
console: Optional console for logging
|
|
416
416
|
"""
|
|
417
417
|
self.watch_paths = watch_paths or [Path('.')]
|
|
418
418
|
self.extensions = extensions or ['.q', '.yaml', '.yml', '.css', '.js', '.html']
|