quantum-framework 0.13.0__tar.gz → 0.15.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.13.0/quantum_framework.egg-info → quantum_framework-0.15.0}/PKG-INFO +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/pyproject.toml +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/migrate.py +15 -3
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/new.py +1 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/deploy.py +1 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/mq.py +2 -2
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/runner.py +10 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/utils.py +1 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/ast_nodes.py +10 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/parser.py +19 -3
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parser.py +31 -9
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/set_parser.py +6 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/invoke_parser.py +6 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/function_parser.py +7 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/param_parser.py +8 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/component.py +31 -53
- quantum_framework-0.15.0/quantum/runtime/conditions.py +54 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/if_executor.py +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/loop_executor.py +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/logging_setup.py +3 -2
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/param_validation.py +34 -2
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/renderer.py +22 -39
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_builder.py +12 -7
- quantum_framework-0.15.0/quantum/runtime/ui_console.py +229 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_html_adapter.py +32 -8
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_html_templates.py +54 -0
- quantum_framework-0.15.0/quantum/runtime/ui_page_renderer.py +123 -0
- quantum_framework-0.15.0/quantum/runtime/ui_view.py +120 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/web_server.py +30 -7
- {quantum_framework-0.13.0 → quantum_framework-0.15.0/quantum_framework.egg-info}/PKG-INFO +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/SOURCES.txt +4 -1
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/requires.txt +1 -0
- quantum_framework-0.13.0/quantum/core/features/query/src/database_service.py +0 -322
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/LICENSE +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/README.md +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/admin.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/build.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/dev.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/docs.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/lint.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/serve.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/test.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/hot_reload.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/jobs.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/pkg.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/server_process.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/base_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/cli.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/expression_transformer.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/javascript/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/javascript/generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/optimizer.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/python/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/python/generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/python/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/transpiler.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/config_env.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/expression_diagnostics.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/expression_stdlib.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/expressions.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/agents/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/agents/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/data_import/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/data_import/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/functions/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/functions/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/invocation/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/invocation/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/loops/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/loops/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/query/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/query/src/query_validators.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/state_management/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/theming/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/theming/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/theming/src/presets.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/websocket/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/guards.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/html_compat.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parser_registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/agent_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/llm_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/team_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/base.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/composition/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/composition/import_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/if_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/data_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/query_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/transaction_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/events/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/action_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/return_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/html/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/html/html_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/persistence/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/persistence/persist_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/routing/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/routing/route_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/dump_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/file_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/log_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/mail_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/tiers.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/manifest.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/resolver.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/hooks.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/loader.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/manifest.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/action_handler.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/agent_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ast_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/auth_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/component_composer.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/component_resolver.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/database_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/email_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/error_handler.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/execution_context.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executor_registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/agent_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/llm_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/base.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/redirect_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/set_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/data_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/invoke_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/query_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/file_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/log_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/expression_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/file_upload_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/function_registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/game_builder.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/game_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/game_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/godot_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/godot_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/job_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/knowledge_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/llm_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/llm_providers.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/llm_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/message_broker.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/message_queue_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/pypy_compat.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/python_bridge.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/query_validators.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/service_container.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/terminal_builder.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/terminal_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/terminal_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/testing_builder.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/testing_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/testing_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_desktop_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_desktop_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_mobile_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_textual_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_textual_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_tokens.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_validator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/validators.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/websocket_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/websocket_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/websocket_transport.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/wsgi.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/services.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/utils/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/assets/quantum-admin.css +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/audit_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/auth_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/component_discovery.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/config_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/connector_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/crud.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/database.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/db_setup_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/deploy_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/docker_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/environment_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/git_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/health_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/job_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/log_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/main.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/models.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/pipeline_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/resource_manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/schemas.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/secret_manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/settings_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/template_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/test_execution_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/test_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/webhook_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/websocket_manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/_layout/AdminShell.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/agents.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/app/[name].q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/applications.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/component/[...path].q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/components.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/connectors.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/dashboard.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/database.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/features.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/index.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/jobs.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/login.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/logout.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/settings.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/source.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/tests.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/run.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/_base.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/_component_test_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/_yaml_editor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/apps.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/auth.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/components.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/connectors.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/projects.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/repository.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/settings.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/yaml_import.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/entry_points.txt +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/top_level.txt +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/setup.cfg +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_agent.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_animations.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ast_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_cli_commands.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_component_library.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_desktop_bridge.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_expression_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_form_validation.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_e2e.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_engine.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_godot_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_job_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_llm_providers.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_message_broker.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_message_queue.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_mobile_target.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_multi_agent.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_packages.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_plugins.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_pypy_compat.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_python_scripting.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_state_persistence.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_terminal_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_terminal_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_testing_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_testing_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_theming.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_html_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_parity.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_textual_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.15.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.15.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
|
|
@@ -28,6 +28,7 @@ Provides-Extra: dev
|
|
|
28
28
|
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
29
29
|
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
30
30
|
Requires-Dist: pytest-mock>=3.11.1; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-xdist>=3.5; extra == "dev"
|
|
31
32
|
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
32
33
|
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
33
34
|
Provides-Extra: db
|
|
@@ -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.15.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"}
|
|
@@ -35,6 +35,7 @@ dev = [
|
|
|
35
35
|
"pytest>=7.4.0",
|
|
36
36
|
"pytest-cov>=4.1.0",
|
|
37
37
|
"pytest-mock>=3.11.1",
|
|
38
|
+
"pytest-xdist>=3.5",
|
|
38
39
|
"black>=23.0.0",
|
|
39
40
|
"ruff>=0.1.0",
|
|
40
41
|
]
|
|
@@ -32,7 +32,7 @@ class Migration:
|
|
|
32
32
|
@property
|
|
33
33
|
def content(self) -> str:
|
|
34
34
|
if self._content is None:
|
|
35
|
-
self._content = self.path.read_text()
|
|
35
|
+
self._content = self.path.read_text(encoding="utf-8") # DB-8: nunca a codificacao do sistema
|
|
36
36
|
return self._content
|
|
37
37
|
|
|
38
38
|
@property
|
|
@@ -167,6 +167,18 @@ class DatabaseConnection:
|
|
|
167
167
|
self._conn.close()
|
|
168
168
|
|
|
169
169
|
|
|
170
|
+
def _paths_migrations(project_path: Path) -> str:
|
|
171
|
+
"""CFG-3: paths.migrations in quantum.config.yaml (default ./migrations)."""
|
|
172
|
+
try:
|
|
173
|
+
import yaml
|
|
174
|
+
from quantum.core.config_env import expand_env
|
|
175
|
+
with open(project_path / "quantum.config.yaml", encoding="utf-8") as f:
|
|
176
|
+
config = expand_env(yaml.safe_load(f) or {})
|
|
177
|
+
return (config.get("paths") or {}).get("migrations") or "migrations"
|
|
178
|
+
except (OSError, ValueError, AttributeError):
|
|
179
|
+
return "migrations"
|
|
180
|
+
|
|
181
|
+
|
|
170
182
|
class MigrationRunner:
|
|
171
183
|
"""Runs database migrations"""
|
|
172
184
|
|
|
@@ -174,7 +186,7 @@ class MigrationRunner:
|
|
|
174
186
|
|
|
175
187
|
def __init__(self, project_path: Path = None, datasource: str = None):
|
|
176
188
|
self.project_path = project_path or Path.cwd()
|
|
177
|
-
self.migrations_dir = self.project_path /
|
|
189
|
+
self.migrations_dir = self.project_path / _paths_migrations(self.project_path)
|
|
178
190
|
self.db = DatabaseConnection(self.project_path, datasource)
|
|
179
191
|
|
|
180
192
|
def _ensure_migrations_table(self):
|
|
@@ -366,7 +378,7 @@ class MigrationRunner:
|
|
|
366
378
|
click.echo(f"Rolling back {version}: {migration_info['name']}...")
|
|
367
379
|
|
|
368
380
|
# Execute rollback SQL
|
|
369
|
-
self.db.execute_script(down_file.read_text())
|
|
381
|
+
self.db.execute_script(down_file.read_text(encoding="utf-8"))
|
|
370
382
|
|
|
371
383
|
# Remove migration record
|
|
372
384
|
self._remove_migration_record(version)
|
|
@@ -443,7 +443,7 @@ def _create_api_template(project_dir: Path, project_name: str) -> None:
|
|
|
443
443
|
|
|
444
444
|
# Update config for API
|
|
445
445
|
config_path = project_dir / 'quantum.config.yaml'
|
|
446
|
-
config = config_path.read_text()
|
|
446
|
+
config = config_path.read_text(encoding="utf-8")
|
|
447
447
|
config = config.replace('type: api', 'type: microservices')
|
|
448
448
|
config_path.write_text(config)
|
|
449
449
|
|
|
@@ -114,7 +114,7 @@ class QuantumDeployer:
|
|
|
114
114
|
"""Load configuration from file."""
|
|
115
115
|
config_file = Path(config_path)
|
|
116
116
|
if config_file.exists():
|
|
117
|
-
with open(config_file) as f:
|
|
117
|
+
with open(config_file, encoding='utf-8') as f:
|
|
118
118
|
return yaml.safe_load(f) or {}
|
|
119
119
|
return {}
|
|
120
120
|
|
|
@@ -353,7 +353,7 @@ def _handle_mq_publish(broker, args) -> int:
|
|
|
353
353
|
|
|
354
354
|
# Get message body
|
|
355
355
|
if args.file:
|
|
356
|
-
with open(args.file, 'r') as f:
|
|
356
|
+
with open(args.file, 'r', encoding='utf-8') as f:
|
|
357
357
|
body = f.read()
|
|
358
358
|
elif args.message:
|
|
359
359
|
body = args.message
|
|
@@ -388,7 +388,7 @@ def _handle_mq_send(broker, args) -> int:
|
|
|
388
388
|
|
|
389
389
|
# Get message body
|
|
390
390
|
if args.file:
|
|
391
|
-
with open(args.file, 'r') as f:
|
|
391
|
+
with open(args.file, 'r', encoding='utf-8') as f:
|
|
392
392
|
body = f.read()
|
|
393
393
|
elif args.message:
|
|
394
394
|
body = args.message
|
|
@@ -285,6 +285,7 @@ Examples:
|
|
|
285
285
|
quantum start # Start web server (magic!)
|
|
286
286
|
quantum run hello.q # Execute component
|
|
287
287
|
quantum admin # Start the Quantum Admin
|
|
288
|
+
quantum console # The application's pages in the terminal
|
|
288
289
|
quantum run game.q --engine godot # Build Godot 4 project
|
|
289
290
|
quantum run backup-job.q # Execute job
|
|
290
291
|
quantum deploy ./my-app # Deploy application
|
|
@@ -335,6 +336,11 @@ Examples:
|
|
|
335
336
|
# Stop command
|
|
336
337
|
subparsers.add_parser('stop', help='Stop running web server')
|
|
337
338
|
|
|
339
|
+
# Console: the application's pages in the terminal (UI-3)
|
|
340
|
+
console_parser = subparsers.add_parser('console', help="Open the application's pages in the terminal")
|
|
341
|
+
console_parser.add_argument('path', nargs='?', default='/', help='Page to open (default: /)')
|
|
342
|
+
console_parser.add_argument('--config', default='quantum.config.yaml', help='Config file')
|
|
343
|
+
|
|
338
344
|
# Admin command (the screens need the [admin] extra; checked when run)
|
|
339
345
|
from quantum.cli.admin import create_admin_parser
|
|
340
346
|
create_admin_parser(subparsers)
|
|
@@ -401,6 +407,10 @@ Examples:
|
|
|
401
407
|
traceback.print_exc()
|
|
402
408
|
sys.exit(1)
|
|
403
409
|
|
|
410
|
+
elif args.command == 'console':
|
|
411
|
+
from quantum.runtime.ui_console import run_console
|
|
412
|
+
sys.exit(run_console(args.config, args.path))
|
|
413
|
+
|
|
404
414
|
elif args.command == 'admin':
|
|
405
415
|
from quantum.cli.admin import handle_admin
|
|
406
416
|
sys.exit(handle_admin(args))
|
|
@@ -307,7 +307,7 @@ def get_quantum_version() -> str:
|
|
|
307
307
|
# Try to read from version file
|
|
308
308
|
version_file = Path(__file__).parent.parent / '__version__.py'
|
|
309
309
|
if version_file.exists():
|
|
310
|
-
content = version_file.read_text()
|
|
310
|
+
content = version_file.read_text(encoding="utf-8")
|
|
311
311
|
# Parse version = "x.y.z"
|
|
312
312
|
for line in content.splitlines():
|
|
313
313
|
if line.startswith('version'):
|
|
@@ -33,6 +33,11 @@ class UILayoutMixin:
|
|
|
33
33
|
self.ui_id: Optional[str] = None
|
|
34
34
|
self.ui_class: Optional[str] = None
|
|
35
35
|
self.visible: Optional[str] = None
|
|
36
|
+
# UI-2: responsive layout, declared (sm < 640 px, md < 768 px, lg < 1024 px)
|
|
37
|
+
self.stack_below: Optional[str] = None # hbox side by side, stacked below the breakpoint
|
|
38
|
+
self.hide_below: Optional[str] = None
|
|
39
|
+
self.hide_above: Optional[str] = None
|
|
40
|
+
self.grow: Optional[str] = None # "true": takes the room left in its row
|
|
36
41
|
|
|
37
42
|
def _layout_to_dict(self) -> Dict[str, Any]:
|
|
38
43
|
"""Return layout attributes as dict (for to_dict)."""
|
|
@@ -1852,3 +1857,8 @@ class UIDatePickerNode(QuantumNode, UILayoutMixin):
|
|
|
1852
1857
|
|
|
1853
1858
|
def validate(self) -> List[str]:
|
|
1854
1859
|
return self._validate_layout()
|
|
1860
|
+
|
|
1861
|
+
|
|
1862
|
+
def is_ui_node(node) -> bool:
|
|
1863
|
+
"""A ui:* element (UI-1): markup, drawn by a renderer, never executed."""
|
|
1864
|
+
return type(node).__module__ == __name__
|
{quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/parser.py
RENAMED
|
@@ -41,13 +41,16 @@ class UIParseError(Exception):
|
|
|
41
41
|
class UIParser:
|
|
42
42
|
"""Parser for ui: namespace UI elements."""
|
|
43
43
|
|
|
44
|
-
def __init__(self, parent_parser):
|
|
44
|
+
def __init__(self, parent_parser, page_mode: bool = False):
|
|
45
45
|
"""
|
|
46
46
|
Args:
|
|
47
47
|
parent_parser: The main QuantumParser instance, used to parse
|
|
48
48
|
q: namespace children (q:set, q:function, q:if, etc.)
|
|
49
49
|
"""
|
|
50
50
|
self.parent = parent_parser
|
|
51
|
+
# UI-1: inside a served page, HTML children are content too. In a
|
|
52
|
+
# <q:application type="ui"> build they were (and stay) ignored.
|
|
53
|
+
self.page_mode = page_mode
|
|
51
54
|
|
|
52
55
|
# ------------------------------------------------------------------
|
|
53
56
|
# Dispatch
|
|
@@ -130,7 +133,10 @@ class UIParser:
|
|
|
130
133
|
"""Dispatch a ui: element to the correct parse method."""
|
|
131
134
|
method_name = self.UI_TAG_MAP.get(local_name)
|
|
132
135
|
if method_name is None:
|
|
133
|
-
|
|
136
|
+
import difflib
|
|
137
|
+
parecidas = difflib.get_close_matches(local_name, self.UI_TAG_MAP, n=1)
|
|
138
|
+
dica = f"; did you mean <ui:{parecidas[0]}>?" if parecidas else ""
|
|
139
|
+
raise UIParseError(f"Unknown UI tag: <ui:{local_name}>{dica}")
|
|
134
140
|
method = getattr(self, method_name)
|
|
135
141
|
return method(element)
|
|
136
142
|
|
|
@@ -190,6 +196,14 @@ class UIParser:
|
|
|
190
196
|
node.ui_id = element.get('id')
|
|
191
197
|
node.ui_class = element.get('class')
|
|
192
198
|
node.visible = element.get('visible')
|
|
199
|
+
# UI-2: responsive attributes; a breakpoint is sm, md or lg.
|
|
200
|
+
for attr, campo in (('stack-below', 'stack_below'), ('hide-below', 'hide_below'),
|
|
201
|
+
('hide-above', 'hide_above')):
|
|
202
|
+
valor = element.get(attr)
|
|
203
|
+
if valor is not None and valor not in ('sm', 'md', 'lg'):
|
|
204
|
+
raise UIParseError(f'{attr}="{valor}": use sm (640 px), md (768 px) or lg (1024 px)')
|
|
205
|
+
setattr(node, campo, valor)
|
|
206
|
+
node.grow = element.get('grow')
|
|
193
207
|
|
|
194
208
|
# ------------------------------------------------------------------
|
|
195
209
|
# Animation attributes helper
|
|
@@ -233,7 +247,7 @@ class UIParser:
|
|
|
233
247
|
|
|
234
248
|
if ns == 'ui':
|
|
235
249
|
return self.parse_ui_element(local, child)
|
|
236
|
-
elif ns == 'quantum':
|
|
250
|
+
elif ns == 'quantum' or self.page_mode:
|
|
237
251
|
return self.parent._parse_statement(child)
|
|
238
252
|
return None
|
|
239
253
|
|
|
@@ -319,6 +333,7 @@ class UIParser:
|
|
|
319
333
|
def _parse_ui_form(self, element: ET.Element) -> UIFormNode:
|
|
320
334
|
node = UIFormNode()
|
|
321
335
|
node.on_submit = element.get('on-submit')
|
|
336
|
+
node.send = element.get('with')
|
|
322
337
|
|
|
323
338
|
# Validation attributes
|
|
324
339
|
node.validation_mode = element.get('validation', 'both')
|
|
@@ -380,6 +395,7 @@ class UIParser:
|
|
|
380
395
|
node = UIButtonNode()
|
|
381
396
|
node.content = (element.text or '').strip()
|
|
382
397
|
node.on_click = element.get('on-click')
|
|
398
|
+
node.send = element.get('with')
|
|
383
399
|
node.variant = element.get('variant')
|
|
384
400
|
node.disabled = self._parse_bool(element.get('disabled'))
|
|
385
401
|
self._apply_layout_attrs(node, element)
|
|
@@ -62,6 +62,7 @@ from quantum.core.features.testing_engine.src.ast_nodes import (
|
|
|
62
62
|
AuthNode as TestingAuthNode,
|
|
63
63
|
)
|
|
64
64
|
from quantum.core.features.ui_engine.src.parser import UIParser, UIParseError
|
|
65
|
+
from quantum.core.features.ui_engine.src.ast_nodes import is_ui_node
|
|
65
66
|
from quantum.core.features.ui_engine.src.ast_nodes import UIWindowNode
|
|
66
67
|
from quantum.core.features.theming.src import UIThemeNode
|
|
67
68
|
from quantum.core.parser_registry import ParserRegistry
|
|
@@ -575,10 +576,12 @@ class QuantumParser:
|
|
|
575
576
|
|
|
576
577
|
# Parse component-level attributes
|
|
577
578
|
component.port = root.get('port')
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
579
|
+
# A2: accepted and never read by anything — refused, like FN-2/DB-5.
|
|
580
|
+
for attr in ('basePath', 'health', 'metrics', 'trace'):
|
|
581
|
+
if root.get(attr) is not None:
|
|
582
|
+
raise QuantumParseError(
|
|
583
|
+
f'<q:component name="{name}"> {attr}= is not supported: it was accepted '
|
|
584
|
+
f'and never did anything.')
|
|
582
585
|
|
|
583
586
|
# Phase G: Authentication & Security attributes
|
|
584
587
|
require_auth_attr = root.get('require_auth', 'false').lower()
|
|
@@ -704,8 +707,8 @@ class QuantumParser:
|
|
|
704
707
|
return corpo + list(node.else_body)
|
|
705
708
|
if isinstance(node, LoopNode):
|
|
706
709
|
return list(node.body)
|
|
707
|
-
if isinstance(node, (HTMLNode, ComponentCallNode)):
|
|
708
|
-
return list(node
|
|
710
|
+
if isinstance(node, (HTMLNode, ComponentCallNode)) or is_ui_node(node):
|
|
711
|
+
return list(getattr(node, 'children', None) or [])
|
|
709
712
|
return []
|
|
710
713
|
|
|
711
714
|
def renderiza(nodes):
|
|
@@ -713,7 +716,7 @@ class QuantumParser:
|
|
|
713
716
|
if isinstance(node, TextNode):
|
|
714
717
|
if node.content.strip():
|
|
715
718
|
return True
|
|
716
|
-
elif isinstance(node, (HTMLNode, ComponentCallNode)):
|
|
719
|
+
elif isinstance(node, (HTMLNode, ComponentCallNode)) or is_ui_node(node):
|
|
717
720
|
return True
|
|
718
721
|
elif isinstance(node, (IfNode, LoopNode)) and renderiza(filhos(node)):
|
|
719
722
|
return True
|
|
@@ -750,7 +753,7 @@ class QuantumParser:
|
|
|
750
753
|
|
|
751
754
|
def andar(nodes, onde):
|
|
752
755
|
for node in nodes:
|
|
753
|
-
if not isinstance(node, self._RENDERED):
|
|
756
|
+
if not isinstance(node, self._RENDERED) and not is_ui_node(node):
|
|
754
757
|
if onde and onde[0] == 'markup':
|
|
755
758
|
raise QuantumParseError(
|
|
756
759
|
f'{tag(node)} inside {onde[1]} in <q:component name="{component.name}"> '
|
|
@@ -768,6 +771,9 @@ class QuantumParser:
|
|
|
768
771
|
continue
|
|
769
772
|
if isinstance(node, HTMLNode):
|
|
770
773
|
andar(filhos(node), onde if onde and onde[0] == 'markup' else ('markup', f'<{node.tag}>'))
|
|
774
|
+
elif is_ui_node(node):
|
|
775
|
+
rotulo = f'<ui:{type(node).__name__[2:-4].lower()}>'
|
|
776
|
+
andar(filhos(node), onde if onde and onde[0] == 'markup' else ('markup', rotulo))
|
|
771
777
|
elif isinstance(node, ComponentCallNode):
|
|
772
778
|
andar(filhos(node), onde if onde and onde[0] == 'markup'
|
|
773
779
|
else ('markup', f'the content of <{node.component_name}>'))
|
|
@@ -835,6 +841,15 @@ class QuantumParser:
|
|
|
835
841
|
# === MODULAR PARSER REGISTRY (no fallback) ===
|
|
836
842
|
# PHASE 1 DIAGNOSTIC: Legacy fallback disabled to test modular coverage
|
|
837
843
|
if self._use_modular_parsers and self._parser_registry:
|
|
844
|
+
# UI-1: a ui:* element inside a page is a UI node, drawn by
|
|
845
|
+
# UIPageRenderer with the page's runtime doing the logic. First,
|
|
846
|
+
# before the registry: ui:button would otherwise be the HTML <button>.
|
|
847
|
+
if self._get_element_ui_namespace(element) == 'ui':
|
|
848
|
+
try:
|
|
849
|
+
return UIParser(self, page_mode=True).parse_ui_element(element_type, element)
|
|
850
|
+
except UIParseError as exc:
|
|
851
|
+
raise QuantumParseError(str(exc)) from exc
|
|
852
|
+
|
|
838
853
|
# PARSE-1: <q:html>, <q:div> — an HTML element name in the q:
|
|
839
854
|
# namespace. The registry answered for it with the HTML parser, so
|
|
840
855
|
# <q:html value="{post.content}"/> became an empty <html> element
|
|
@@ -1235,9 +1250,16 @@ class QuantumParser:
|
|
|
1235
1250
|
type=element.get('type', 'string'),
|
|
1236
1251
|
required=element.get('required', 'false').lower() == 'true',
|
|
1237
1252
|
default=element.get('default'),
|
|
1238
|
-
validation=element.get('validation'),
|
|
1239
1253
|
description=element.get('description')
|
|
1240
1254
|
)
|
|
1255
|
+
if element.get('validation') is not None:
|
|
1256
|
+
# A2: accepted and never read. The rules are validate=, type=,
|
|
1257
|
+
# pattern=, min/max, minlength/maxlength and enum=.
|
|
1258
|
+
from quantum.core.parser import QuantumParseError
|
|
1259
|
+
raise QuantumParseError(
|
|
1260
|
+
f'<q:param name="{element.get("name", "")}"> validation= is not supported: it was '
|
|
1261
|
+
f'accepted and never did anything. Use type=, pattern=, min/max, '
|
|
1262
|
+
f'minlength/maxlength or enum=.')
|
|
1241
1263
|
|
|
1242
1264
|
# REST-specific
|
|
1243
1265
|
param.source = element.get('source', 'auto')
|
|
@@ -53,7 +53,12 @@ class SetParser(BaseTagParser):
|
|
|
53
53
|
set_node.nullable = self.get_bool_attr(element, 'nullable', True)
|
|
54
54
|
set_node.validate_rule = self.get_attr(element, 'validate')
|
|
55
55
|
set_node.pattern = self.get_attr(element, 'pattern')
|
|
56
|
-
|
|
56
|
+
if element.get('mask') is not None:
|
|
57
|
+
# A2: accepted and never applied.
|
|
58
|
+
from quantum.core.parser import QuantumParseError
|
|
59
|
+
raise QuantumParseError(
|
|
60
|
+
f'<q:set name="{set_node.name}"> mask= is not supported: it was accepted and '
|
|
61
|
+
f'never did anything. To validate a format use pattern=.')
|
|
57
62
|
set_node.range = self.get_attr(element, 'range')
|
|
58
63
|
set_node.enum = self.get_attr(element, 'enum')
|
|
59
64
|
set_node.unique = self.get_attr(element, 'unique')
|
{quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/invoke_parser.py
RENAMED
|
@@ -70,7 +70,12 @@ class InvokeParser(BaseTagParser):
|
|
|
70
70
|
|
|
71
71
|
# Response handling
|
|
72
72
|
invoke_node.response_format = self.get_attr(element, 'responseFormat', 'auto')
|
|
73
|
-
|
|
73
|
+
if element.get('transform') is not None:
|
|
74
|
+
# A2: accepted and never applied.
|
|
75
|
+
from quantum.core.parser import QuantumParseError
|
|
76
|
+
raise QuantumParseError(
|
|
77
|
+
f'<q:invoke name="{invoke_node.name}"> transform= is not supported: it was '
|
|
78
|
+
f'accepted and never did anything. Transform the result with q:set.')
|
|
74
79
|
invoke_node.cache = self.get_bool_attr(element, 'cache', False)
|
|
75
80
|
invoke_node.ttl = self.get_int_attr(element, 'ttl', 0) or None
|
|
76
81
|
invoke_node.result = self.get_attr(element, 'result')
|
|
@@ -65,6 +65,13 @@ class FunctionParser(BaseTagParser):
|
|
|
65
65
|
|
|
66
66
|
# Core attributes
|
|
67
67
|
func_node.return_type = element.get('returnType', 'any')
|
|
68
|
+
# FN-4: returnType is checked on every return (see ComponentRuntime).
|
|
69
|
+
from quantum.runtime.param_validation import RETURN_TYPES
|
|
70
|
+
if func_node.return_type.lower() not in RETURN_TYPES:
|
|
71
|
+
from quantum.core.parser import QuantumParseError
|
|
72
|
+
raise QuantumParseError(
|
|
73
|
+
f'<q:function name="{name}"> returnType="{func_node.return_type}" is not a type; '
|
|
74
|
+
f'use one of: {", ".join(sorted(RETURN_TYPES))}')
|
|
68
75
|
func_node.description = element.get('description')
|
|
69
76
|
func_node.hint = element.get('hint')
|
|
70
77
|
|
{quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/param_parser.py
RENAMED
|
@@ -29,9 +29,16 @@ class ParamParser(BaseTagParser):
|
|
|
29
29
|
type=element.get('type', 'string'),
|
|
30
30
|
required=element.get('required', 'false').lower() == 'true',
|
|
31
31
|
default=element.get('default'),
|
|
32
|
-
validation=element.get('validation'),
|
|
33
32
|
description=element.get('description')
|
|
34
33
|
)
|
|
34
|
+
if element.get('validation') is not None:
|
|
35
|
+
# A2: accepted and never read. The rules are validate=, type=,
|
|
36
|
+
# pattern=, min/max, minlength/maxlength and enum=.
|
|
37
|
+
from quantum.core.parser import QuantumParseError
|
|
38
|
+
raise QuantumParseError(
|
|
39
|
+
f'<q:param name="{element.get("name", "")}"> validation= is not supported: it was '
|
|
40
|
+
f'accepted and never did anything. Use type=, pattern=, min/max, '
|
|
41
|
+
f'minlength/maxlength or enum=.')
|
|
35
42
|
|
|
36
43
|
# REST-specific
|
|
37
44
|
param.source = element.get('source', 'auto')
|
|
@@ -68,6 +68,8 @@ from quantum.runtime.executors.control_flow.loop_executor import (
|
|
|
68
68
|
as_return_value, produced_return,
|
|
69
69
|
)
|
|
70
70
|
from quantum.runtime.service_container import ServiceContainer
|
|
71
|
+
from quantum.runtime.conditions import evaluate_condition
|
|
72
|
+
from quantum.core.features.ui_engine.src.ast_nodes import is_ui_node
|
|
71
73
|
import re
|
|
72
74
|
import logging
|
|
73
75
|
|
|
@@ -424,7 +426,8 @@ class ComponentRuntime:
|
|
|
424
426
|
# and served a 500 the moment the legacy if-elif chain that used to
|
|
425
427
|
# swallow it was removed.
|
|
426
428
|
ComponentCallNode,
|
|
427
|
-
)):
|
|
429
|
+
)) or is_ui_node(statement):
|
|
430
|
+
# ui:* inside a page is markup (UI-1): the renderer draws it.
|
|
428
431
|
return None
|
|
429
432
|
|
|
430
433
|
# <q:return> aninhado dentro de q:if / q:else / q:loop. Nao tem
|
|
@@ -462,57 +465,8 @@ class ComponentRuntime:
|
|
|
462
465
|
return None
|
|
463
466
|
|
|
464
467
|
def _evaluate_condition(self, condition: str, context: Dict[str, Any], guard: bool = False) -> bool:
|
|
465
|
-
"""
|
|
466
|
-
|
|
467
|
-
return False
|
|
468
|
-
|
|
469
|
-
# Evaluate the condition as an expression, without interpolating any
|
|
470
|
-
# values into it first. Stripping the braces leaves the variable NAMES
|
|
471
|
-
# in place for the evaluator to resolve, so no value is ever parsed as
|
|
472
|
-
# syntax — unlike the databinding-then-evaluate path below, which
|
|
473
|
-
# assembles code out of data. Same change as HTMLRenderer.
|
|
474
|
-
stripped = self._databinding_pattern.sub(lambda m: m.group(1), condition).strip()
|
|
475
|
-
|
|
476
|
-
# IF-2: `1` and `{1}` are the number 1, true. There used to be a
|
|
477
|
-
# regex-quantifier check here that made every such condition false;
|
|
478
|
-
# a condition is never a regex, and HTMLRenderer never had the check.
|
|
479
|
-
try:
|
|
480
|
-
return bool(self._expressions.evaluate(stripped, context or {}, absent_scope_key_is_none=True))
|
|
481
|
-
except UndefinedError as exc:
|
|
482
|
-
if guard:
|
|
483
|
-
# AUTH-6: a guard decides whether the page (and its actions)
|
|
484
|
-
# may run. Reading a failure as false lets everything through,
|
|
485
|
-
# so in a guard it is an error: the page fails closed.
|
|
486
|
-
raise ExpressionError(
|
|
487
|
-
f"guard condition {condition!r} could not be evaluated: {exc}. A guard "
|
|
488
|
-
f"must decide; test each part first, e.g. "
|
|
489
|
-
f"`not session.user or not session.user.is_admin`") from exc
|
|
490
|
-
# EXPR-5: a condition is a presence test. A name, key or attribute
|
|
491
|
-
# that does not exist makes it FALSE (never true, see below).
|
|
492
|
-
# Anything else — a syntax error, a function that does not exist —
|
|
493
|
-
# propagates as an error: reading those as false is how
|
|
494
|
-
# `age >= 18 && ok` took the else branch for every input.
|
|
495
|
-
#
|
|
496
|
-
#
|
|
497
|
-
# It used to fall through to a chain that interpolated the variable
|
|
498
|
-
# VALUES into the text and took the truthiness of the result. For a
|
|
499
|
-
# condition like `session.user.is_admin` on a logged-out request
|
|
500
|
-
# that produced the literal string 'session.user.is_admin', which
|
|
501
|
-
# is non-empty and therefore truthy — so the q:if fired its admin
|
|
502
|
-
# branch and its q:else never did. A condition failing open is an
|
|
503
|
-
# authorization bypass by construction. Reported by two audit
|
|
504
|
-
# dimensions, reproduced directly, and the same fix as HTMLRenderer.
|
|
505
|
-
#
|
|
506
|
-
# That fallback chain also fed ExpressionCache's compile()+eval(),
|
|
507
|
-
# whose regex denylist is bypassable by splitting a dunder across
|
|
508
|
-
# adjacent string literals — so removing it closes a latent RCE
|
|
509
|
-
# path as well as the fail-open.
|
|
510
|
-
report_unresolved(stripped, ExpressionError(
|
|
511
|
-
f"condition {condition!r} could not be evaluated; treated as false"
|
|
512
|
-
))
|
|
513
|
-
return False
|
|
514
|
-
except ExpressionError as exc:
|
|
515
|
-
raise ExpressionError(f"condition {condition!r} could not be evaluated: {exc}") from exc
|
|
468
|
+
"""A condition by the language's rules — see quantum/runtime/conditions.py."""
|
|
469
|
+
return evaluate_condition(self._expressions, condition, context, guard=guard)
|
|
516
470
|
|
|
517
471
|
def _apply_databinding(self, text: str, context: Dict[str, Any]) -> Any:
|
|
518
472
|
"""Apply variable databinding to text using {variable} syntax.
|
|
@@ -839,7 +793,31 @@ class ComponentRuntime:
|
|
|
839
793
|
finally:
|
|
840
794
|
self.execution_context = previous_context
|
|
841
795
|
|
|
842
|
-
return as_return_value(result)
|
|
796
|
+
return self._check_return_type(func_node, as_return_value(result))
|
|
797
|
+
|
|
798
|
+
def _check_return_type(self, func_node: FunctionNode, valor: Any) -> Any:
|
|
799
|
+
"""FN-4: the value a q:function returns matches its returnType.
|
|
800
|
+
|
|
801
|
+
returnType= was accepted and never read: returnType="number" returned
|
|
802
|
+
whatever the body produced.
|
|
803
|
+
"""
|
|
804
|
+
tipo = (getattr(func_node, 'return_type', None) or 'any').lower()
|
|
805
|
+
if tipo == 'any':
|
|
806
|
+
return valor
|
|
807
|
+
if tipo == 'void':
|
|
808
|
+
if valor is not None:
|
|
809
|
+
raise ComponentExecutionError(
|
|
810
|
+
f'q:function "{func_node.name}" declares returnType="void" but returned {valor!r}')
|
|
811
|
+
return valor
|
|
812
|
+
if valor is None:
|
|
813
|
+
raise ComponentExecutionError(
|
|
814
|
+
f'q:function "{func_node.name}" declares returnType="{tipo}" but returned nothing')
|
|
815
|
+
from types import SimpleNamespace
|
|
816
|
+
convertido, erro = param_validation.coerce(SimpleNamespace(type=tipo, name=func_node.name), valor)
|
|
817
|
+
if erro:
|
|
818
|
+
raise ComponentExecutionError(
|
|
819
|
+
f'q:function "{func_node.name}" declares returnType="{tipo}" but returned {valor!r}')
|
|
820
|
+
return convertido
|
|
843
821
|
|
|
844
822
|
def _validate_function_args(self, func_node: FunctionNode, args: Dict[str, Any], only=None):
|
|
845
823
|
"""validate=/range=/enum= rules of the q:param (QuantumValidators)."""
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""The one place a `condition` is evaluated (q:if, q:elseif, guards).
|
|
2
|
+
|
|
3
|
+
ComponentRuntime (statements) and HTMLRenderer (markup) each had their own
|
|
4
|
+
copy of this function. They drifted: IF-2 (`condition="1"` was false) existed
|
|
5
|
+
in one and not the other. Both call this now.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import re
|
|
9
|
+
from typing import Any, Dict
|
|
10
|
+
|
|
11
|
+
from quantum.core.expression_diagnostics import report_unresolved
|
|
12
|
+
from quantum.core.expressions import ExpressionError, ExpressionEvaluator, UndefinedError
|
|
13
|
+
|
|
14
|
+
_BRACES = re.compile(r'\{([^}]+)\}')
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def evaluate_condition(evaluator: ExpressionEvaluator, condition: str,
|
|
18
|
+
variables: Dict[str, Any], guard: bool = False) -> bool:
|
|
19
|
+
"""True or False for a condition, by the rules of SPEC IF-2, EXPR-5, EXPR-8, AUTH-6.
|
|
20
|
+
|
|
21
|
+
The condition is evaluated as an expression with the braces stripped:
|
|
22
|
+
the variable NAMES stay in place for the evaluator to resolve, so no
|
|
23
|
+
value is ever parsed as syntax. (It used to interpolate the values into
|
|
24
|
+
the text and eval() the result — code assembled out of data; a record
|
|
25
|
+
named "'; __import__(...)" became executable. PUBLIC_RELEASE_PLAN P0.1.)
|
|
26
|
+
"""
|
|
27
|
+
if not condition:
|
|
28
|
+
return False
|
|
29
|
+
stripped = _BRACES.sub(lambda m: m.group(1), condition).strip()
|
|
30
|
+
try:
|
|
31
|
+
# EXPR-8: a key a scope does not have (session.userId before login)
|
|
32
|
+
# is None here, so `not session.authenticated` is true for a visitor.
|
|
33
|
+
return bool(evaluator.evaluate(stripped, variables or {}, absent_scope_key_is_none=True))
|
|
34
|
+
except UndefinedError as exc:
|
|
35
|
+
if guard:
|
|
36
|
+
# AUTH-6: a guard decides whether the page and its actions run.
|
|
37
|
+
# Reading a failure as false would let everything through, so in
|
|
38
|
+
# a guard it is an error: the page fails closed.
|
|
39
|
+
raise ExpressionError(
|
|
40
|
+
f"guard condition {condition!r} could not be evaluated: {exc}. A guard "
|
|
41
|
+
f"must decide; test each part first, e.g. "
|
|
42
|
+
f"`not session.user or not session.user.is_admin`") from exc
|
|
43
|
+
# EXPR-5: a condition is a presence test — a missing name, key or
|
|
44
|
+
# attribute makes it FALSE, never true. Before, the literal
|
|
45
|
+
# placeholder 'session.user.is_admin' came back as a non-empty string,
|
|
46
|
+
# read as true: the admin branch rendered for a logged-out visitor.
|
|
47
|
+
report_unresolved(stripped, ExpressionError(
|
|
48
|
+
f"condition {condition!r} could not be evaluated; treated as false"))
|
|
49
|
+
return False
|
|
50
|
+
except ExpressionError as exc:
|
|
51
|
+
# A syntax error or a function that does not exist is an error:
|
|
52
|
+
# reading it as false is how `age >= 18 && ok` took the else branch
|
|
53
|
+
# for every input.
|
|
54
|
+
raise ExpressionError(f"condition {condition!r} could not be evaluated: {exc}") from exc
|
|
@@ -5,6 +5,7 @@ Handles conditional execution with elseif and else blocks.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
from typing import Any, List, Dict, Type
|
|
8
|
+
from quantum.core.features.ui_engine.src.ast_nodes import is_ui_node
|
|
8
9
|
from quantum.runtime.executors.base import BaseExecutor, ExecutorError
|
|
9
10
|
from quantum.runtime.executors.control_flow.loop_executor import produced_return
|
|
10
11
|
from quantum.core.features.conditionals.src.ast_node import IfNode
|
|
@@ -84,7 +85,7 @@ class IfExecutor(BaseExecutor):
|
|
|
84
85
|
for statement in statements:
|
|
85
86
|
if isinstance(statement, QuantumReturn):
|
|
86
87
|
return self.resolve_value(statement.value, context)
|
|
87
|
-
elif isinstance(statement, _RENDER_ONLY_NODE_TYPES):
|
|
88
|
+
elif (isinstance(statement, _RENDER_ONLY_NODE_TYPES) or is_ui_node(statement)):
|
|
88
89
|
continue
|
|
89
90
|
else:
|
|
90
91
|
# Use registry to execute child statements
|
|
@@ -6,6 +6,7 @@ Handles all loop types: range, array, list, query.
|
|
|
6
6
|
|
|
7
7
|
from typing import Any, List, Dict, Type
|
|
8
8
|
import json
|
|
9
|
+
from quantum.core.features.ui_engine.src.ast_nodes import is_ui_node
|
|
9
10
|
from quantum.runtime.executors.base import BaseExecutor, ExecutorError
|
|
10
11
|
from quantum.core.features.loops.src.ast_node import LoopNode
|
|
11
12
|
from quantum.core.features.conditionals.src.ast_node import IfNode
|
|
@@ -244,7 +245,7 @@ class LoopExecutor(BaseExecutor):
|
|
|
244
245
|
"""Execute a statement inside a loop body"""
|
|
245
246
|
if isinstance(statement, QuantumReturn):
|
|
246
247
|
return self.resolve_value(statement.value, context)
|
|
247
|
-
elif isinstance(statement, _RENDER_ONLY_NODE_TYPES):
|
|
248
|
+
elif (isinstance(statement, _RENDER_ONLY_NODE_TYPES) or is_ui_node(statement)):
|
|
248
249
|
# Text/HTML content is handled by HTMLRenderer._render_loop(),
|
|
249
250
|
# which independently re-iterates and renders the body — it is
|
|
250
251
|
# not meant to be executed here.
|
|
@@ -84,14 +84,15 @@ def setup_logging(config: Dict[str, Any]) -> logging.Logger:
|
|
|
84
84
|
logger.handlers.clear()
|
|
85
85
|
|
|
86
86
|
datefmt = '%Y-%m-%d %H:%M:%S'
|
|
87
|
-
|
|
87
|
+
# CFG-3: logging.format was documented here and never read.
|
|
88
|
+
plain_fmt = log_config.get('format') or '%(asctime)s %(levelname)-8s %(name)s - %(message)s'
|
|
88
89
|
|
|
89
90
|
# Console handler with color support
|
|
90
91
|
if enable_console:
|
|
91
92
|
console_handler = logging.StreamHandler(sys.stderr)
|
|
92
93
|
console_handler.setLevel(level)
|
|
93
94
|
use_color = _supports_color()
|
|
94
|
-
colored_fmt = '%(asctime)s %(levelname)s %(name)s - %(message)s'
|
|
95
|
+
colored_fmt = log_config.get('format') or '%(asctime)s %(levelname)s %(name)s - %(message)s'
|
|
95
96
|
formatter = ColoredFormatter(colored_fmt, datefmt=datefmt, use_color=use_color)
|
|
96
97
|
console_handler.setFormatter(formatter)
|
|
97
98
|
logger.addHandler(console_handler)
|