quantum-framework 0.13.0__tar.gz → 0.14.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.14.0}/PKG-INFO +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/pyproject.toml +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/migrate.py +13 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parser.py +22 -6
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/control_flow/set_parser.py +6 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/data/invoke_parser.py +6 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/functions/function_parser.py +7 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/functions/param_parser.py +8 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/component.py +28 -52
- quantum_framework-0.14.0/quantum/runtime/conditions.py +54 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/logging_setup.py +3 -2
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/param_validation.py +34 -2
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/renderer.py +12 -38
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_builder.py +12 -7
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/web_server.py +14 -7
- {quantum_framework-0.13.0 → quantum_framework-0.14.0/quantum_framework.egg-info}/PKG-INFO +2 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_framework.egg-info/SOURCES.txt +1 -1
- {quantum_framework-0.13.0 → quantum_framework-0.14.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.14.0}/LICENSE +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/README.md +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/admin.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/build.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/dev.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/docs.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/lint.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/new.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/serve.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/commands/test.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/deploy.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/hot_reload.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/jobs.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/mq.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/pkg.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/runner.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/server_process.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/cli/utils.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/base_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/cli.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/expression_transformer.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/javascript/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/javascript/generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/optimizer.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/python/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/python/generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/python/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/compiler/transpiler.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/config_env.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/expression_diagnostics.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/expression_stdlib.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/expressions.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/agents/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/agents/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/data_import/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/data_import/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/dump/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/dump/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/dump/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/dump/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/functions/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/functions/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/invocation/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/invocation/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/logging/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/logging/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/logging/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/logging/src/runtime.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/loops/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/loops/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/query/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/query/src/query_validators.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/state_management/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/theming/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/theming/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/theming/src/presets.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/ui_engine/src/ast_nodes.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/ui_engine/src/parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/websocket/src/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/guards.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/html_compat.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parser_registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/ai/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/ai/agent_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/ai/llm_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/ai/team_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/base.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/composition/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/composition/import_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/control_flow/if_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/data/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/data/data_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/data/query_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/data/transaction_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/events/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/forms/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/forms/action_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/functions/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/functions/return_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/html/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/html/html_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/jobs/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/messaging/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/persistence/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/persistence/persist_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/routing/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/routing/route_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/scripting/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/services/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/services/dump_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/services/file_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/services/log_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/parsers/services/mail_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/core/tiers.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/packages/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/packages/manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/packages/manifest.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/packages/registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/packages/resolver.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/plugins/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/plugins/hooks.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/plugins/loader.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/plugins/manifest.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/plugins/registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/action_handler.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/adapters/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/agent_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ast_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/auth_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/component_composer.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/component_resolver.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/database_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/email_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/error_handler.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/execution_context.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executor_registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/ai/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/ai/agent_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/ai/llm_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/base.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/control_flow/if_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/control_flow/loop_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/control_flow/redirect_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/control_flow/set_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/data/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/data/data_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/data/invoke_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/data/query_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/services/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/services/file_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/services/log_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/expression_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/file_upload_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/function_registry.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/game_builder.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/game_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/game_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/godot_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/godot_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/job_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/knowledge_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/llm_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/llm_providers.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/llm_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/message_broker.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/message_queue_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/pypy_compat.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/python_bridge.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/query_validators.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/service_container.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/terminal_builder.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/terminal_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/terminal_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/testing_builder.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/testing_code_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/testing_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_desktop_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_desktop_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_html_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_html_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_mobile_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_textual_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_textual_templates.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_tokens.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/ui_validator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/validators.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/websocket_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/websocket_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/websocket_transport.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/runtime/wsgi.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/services.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum/utils/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/assets/quantum-admin.css +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/audit_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/auth_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/component_discovery.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/config_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/connector_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/crud.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/database.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/db_setup_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/deploy_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/docker_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/environment_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/git_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/health_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/job_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/log_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/main.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/models.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/pipeline_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/resource_manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/schemas.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/secret_manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/settings_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/template_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/test_execution_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/test_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/webhook_service.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/backend/websocket_manager.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/_layout/AdminShell.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/agents.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/app/[name].q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/applications.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/component/[...path].q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/components.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/connectors.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/dashboard.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/database.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/features.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/index.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/jobs.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/login.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/logout.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/settings.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/source.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/components/admin/tests.q +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/run.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/__init__.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/_base.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/_component_test_generator.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/_yaml_editor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/apps.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/auth.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/components.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/connectors.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/projects.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/repository.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/settings.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_admin/services/yaml_import.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_framework.egg-info/entry_points.txt +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_framework.egg-info/top_level.txt +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/setup.cfg +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_agent.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_animations.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_ast_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_cli_commands.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_component_library.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_desktop_bridge.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_expression_cache.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_form_validation.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_game_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_game_e2e.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_game_engine.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_game_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_godot_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_job_executor.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_llm_providers.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_message_broker.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_message_queue.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_mobile_target.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_multi_agent.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_packages.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_plugins.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_pypy_compat.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_python_scripting.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_state_persistence.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_terminal_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_terminal_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_testing_codegen.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_testing_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_theming.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_ui_html_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_ui_parity.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_ui_parser.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.0}/tests/test_ui_textual_adapter.py +0 -0
- {quantum_framework-0.13.0 → quantum_framework-0.14.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.14.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.14.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
|
]
|
|
@@ -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):
|
|
@@ -575,10 +575,12 @@ class QuantumParser:
|
|
|
575
575
|
|
|
576
576
|
# Parse component-level attributes
|
|
577
577
|
component.port = root.get('port')
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
578
|
+
# A2: accepted and never read by anything — refused, like FN-2/DB-5.
|
|
579
|
+
for attr in ('basePath', 'health', 'metrics', 'trace'):
|
|
580
|
+
if root.get(attr) is not None:
|
|
581
|
+
raise QuantumParseError(
|
|
582
|
+
f'<q:component name="{name}"> {attr}= is not supported: it was accepted '
|
|
583
|
+
f'and never did anything.')
|
|
582
584
|
|
|
583
585
|
# Phase G: Authentication & Security attributes
|
|
584
586
|
require_auth_attr = root.get('require_auth', 'false').lower()
|
|
@@ -867,7 +869,14 @@ class QuantumParser:
|
|
|
867
869
|
|
|
868
870
|
if self._is_html_element(element):
|
|
869
871
|
if self._parser_registry.html_parser.can_parse(element_type):
|
|
870
|
-
|
|
872
|
+
node = self._parser_registry.html_parser.parse(element)
|
|
873
|
+
# UI-0: a ui:* element inside a page. Parsed as before
|
|
874
|
+
# (examples and tests load these files), but flagged so the
|
|
875
|
+
# renderer refuses it instead of emitting <window>/<vbox>,
|
|
876
|
+
# which no browser lays out.
|
|
877
|
+
if self._get_element_ui_namespace(element) == 'ui':
|
|
878
|
+
node.ui_tag = element_type
|
|
879
|
+
return node
|
|
871
880
|
|
|
872
881
|
# PARSE-1: a q: tag nobody parses is an error. It used to return
|
|
873
882
|
# None here and vanish — <q:sett>, <q:retrun> and <q:iff> ran as if
|
|
@@ -1235,9 +1244,16 @@ class QuantumParser:
|
|
|
1235
1244
|
type=element.get('type', 'string'),
|
|
1236
1245
|
required=element.get('required', 'false').lower() == 'true',
|
|
1237
1246
|
default=element.get('default'),
|
|
1238
|
-
validation=element.get('validation'),
|
|
1239
1247
|
description=element.get('description')
|
|
1240
1248
|
)
|
|
1249
|
+
if element.get('validation') is not None:
|
|
1250
|
+
# A2: accepted and never read. The rules are validate=, type=,
|
|
1251
|
+
# pattern=, min/max, minlength/maxlength and enum=.
|
|
1252
|
+
from quantum.core.parser import QuantumParseError
|
|
1253
|
+
raise QuantumParseError(
|
|
1254
|
+
f'<q:param name="{element.get("name", "")}"> validation= is not supported: it was '
|
|
1255
|
+
f'accepted and never did anything. Use type=, pattern=, min/max, '
|
|
1256
|
+
f'minlength/maxlength or enum=.')
|
|
1241
1257
|
|
|
1242
1258
|
# REST-specific
|
|
1243
1259
|
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.14.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.14.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,7 @@ 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
|
|
71
72
|
import re
|
|
72
73
|
import logging
|
|
73
74
|
|
|
@@ -462,57 +463,8 @@ class ComponentRuntime:
|
|
|
462
463
|
return None
|
|
463
464
|
|
|
464
465
|
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
|
|
466
|
+
"""A condition by the language's rules — see quantum/runtime/conditions.py."""
|
|
467
|
+
return evaluate_condition(self._expressions, condition, context, guard=guard)
|
|
516
468
|
|
|
517
469
|
def _apply_databinding(self, text: str, context: Dict[str, Any]) -> Any:
|
|
518
470
|
"""Apply variable databinding to text using {variable} syntax.
|
|
@@ -839,7 +791,31 @@ class ComponentRuntime:
|
|
|
839
791
|
finally:
|
|
840
792
|
self.execution_context = previous_context
|
|
841
793
|
|
|
842
|
-
return as_return_value(result)
|
|
794
|
+
return self._check_return_type(func_node, as_return_value(result))
|
|
795
|
+
|
|
796
|
+
def _check_return_type(self, func_node: FunctionNode, valor: Any) -> Any:
|
|
797
|
+
"""FN-4: the value a q:function returns matches its returnType.
|
|
798
|
+
|
|
799
|
+
returnType= was accepted and never read: returnType="number" returned
|
|
800
|
+
whatever the body produced.
|
|
801
|
+
"""
|
|
802
|
+
tipo = (getattr(func_node, 'return_type', None) or 'any').lower()
|
|
803
|
+
if tipo == 'any':
|
|
804
|
+
return valor
|
|
805
|
+
if tipo == 'void':
|
|
806
|
+
if valor is not None:
|
|
807
|
+
raise ComponentExecutionError(
|
|
808
|
+
f'q:function "{func_node.name}" declares returnType="void" but returned {valor!r}')
|
|
809
|
+
return valor
|
|
810
|
+
if valor is None:
|
|
811
|
+
raise ComponentExecutionError(
|
|
812
|
+
f'q:function "{func_node.name}" declares returnType="{tipo}" but returned nothing')
|
|
813
|
+
from types import SimpleNamespace
|
|
814
|
+
convertido, erro = param_validation.coerce(SimpleNamespace(type=tipo, name=func_node.name), valor)
|
|
815
|
+
if erro:
|
|
816
|
+
raise ComponentExecutionError(
|
|
817
|
+
f'q:function "{func_node.name}" declares returnType="{tipo}" but returned {valor!r}')
|
|
818
|
+
return convertido
|
|
843
819
|
|
|
844
820
|
def _validate_function_args(self, func_node: FunctionNode, args: Dict[str, Any], only=None):
|
|
845
821
|
"""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
|
|
@@ -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)
|
|
@@ -45,6 +45,9 @@ FILE_TYPES = ('file', 'binary', 'upload')
|
|
|
45
45
|
# receber como veio.
|
|
46
46
|
PASSTHROUGH_TYPES = ('string', 'text', 'array', 'object', 'any', 'json')
|
|
47
47
|
|
|
48
|
+
# FN-4: what q:function returnType= accepts ('void': returns nothing).
|
|
49
|
+
RETURN_TYPES = frozenset(INT_TYPES + FLOAT_TYPES + PASSTHROUGH_TYPES + ('boolean', 'email', 'url', 'void'))
|
|
50
|
+
|
|
48
51
|
_EMAIL = re.compile(r'^[^@\s]+@[^@\s]+\.[^@\s]+$')
|
|
49
52
|
_URL = re.compile(r'^https?://', re.IGNORECASE)
|
|
50
53
|
|
|
@@ -128,9 +131,13 @@ def check_rules(param_def, value: Any) -> List[str]:
|
|
|
128
131
|
errors: List[str] = []
|
|
129
132
|
name = getattr(param_def, 'name', '?')
|
|
130
133
|
|
|
131
|
-
# Nada de comprimento, faixa ou padrao faz sentido sobre um arquivo
|
|
132
|
-
#
|
|
134
|
+
# Nada de comprimento, faixa ou padrao faz sentido sobre um arquivo. O que
|
|
135
|
+
# vale para um upload e accept= (ACT-11).
|
|
133
136
|
if is_uploaded_file(value):
|
|
137
|
+
accept = getattr(param_def, 'accept', None)
|
|
138
|
+
if accept and not accepts_file(value, accept):
|
|
139
|
+
errors.append(f"Parameter '{name}' accepts {accept}; got "
|
|
140
|
+
f"'{getattr(value, 'filename', '')}'")
|
|
134
141
|
return errors
|
|
135
142
|
|
|
136
143
|
minimo = getattr(param_def, 'min', None)
|
|
@@ -184,3 +191,28 @@ def check_rules(param_def, value: Any) -> List[str]:
|
|
|
184
191
|
f"Parameter '{name}' must be one of: {', '.join(allowed)}")
|
|
185
192
|
|
|
186
193
|
return errors
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def accepts_file(upload, accept: str) -> bool:
|
|
197
|
+
"""ACT-11: does an upload match an HTML-style accept list (".pdf", "image/*")?
|
|
198
|
+
|
|
199
|
+
The Content-Type an upload declares comes from the browser, so a MIME
|
|
200
|
+
pattern is matched against the type the FILE NAME implies as well: an
|
|
201
|
+
.exe sent as image/png does not pass image/*. An extension pattern is
|
|
202
|
+
matched against the file name.
|
|
203
|
+
"""
|
|
204
|
+
import mimetypes
|
|
205
|
+
nome = (getattr(upload, 'filename', '') or '').lower()
|
|
206
|
+
pelo_nome = (mimetypes.guess_type(nome)[0] or '').lower()
|
|
207
|
+
declarado = (getattr(upload, 'content_type', '') or '').split(';')[0].strip().lower()
|
|
208
|
+
for item in (a.strip().lower() for a in accept.split(',') if a.strip()):
|
|
209
|
+
if item.startswith('.'):
|
|
210
|
+
if nome.endswith(item):
|
|
211
|
+
return True
|
|
212
|
+
elif item.endswith('/*'):
|
|
213
|
+
base = item[:-1]
|
|
214
|
+
if pelo_nome.startswith(base) and (not declarado or declarado.startswith(base)):
|
|
215
|
+
return True
|
|
216
|
+
elif pelo_nome == item and (not declarado or declarado == item):
|
|
217
|
+
return True
|
|
218
|
+
return False
|
|
@@ -27,6 +27,7 @@ from quantum.core.features.conditionals.src.ast_node import IfNode
|
|
|
27
27
|
from quantum.core.features.loops.src.ast_node import LoopNode
|
|
28
28
|
from quantum.core.features.state_management.src.ast_node import SetNode
|
|
29
29
|
from quantum.runtime.execution_context import ExecutionContext
|
|
30
|
+
from quantum.runtime.conditions import evaluate_condition
|
|
30
31
|
|
|
31
32
|
logger = logging.getLogger('quantum.renderer')
|
|
32
33
|
|
|
@@ -163,6 +164,15 @@ class HTMLRenderer:
|
|
|
163
164
|
Returns:
|
|
164
165
|
HTML string
|
|
165
166
|
"""
|
|
167
|
+
ui_tag = getattr(node, 'ui_tag', None)
|
|
168
|
+
if ui_tag:
|
|
169
|
+
# UI-0: until 0.15, ui:* is compiled from <q:application type="ui">
|
|
170
|
+
# (quantum run app.q --target html|textual|desktop). Served inside a
|
|
171
|
+
# page it came out as <window>/<vbox> tags no browser lays out.
|
|
172
|
+
raise ValueError(
|
|
173
|
+
f"<ui:{ui_tag}> cannot be used inside a page yet: ui:* elements are "
|
|
174
|
+
f"compiled from <q:application type=\"ui\"> with `quantum run app.q "
|
|
175
|
+
f"--target html`. Using them inside pages arrives in Quantum 0.15.")
|
|
166
176
|
|
|
167
177
|
# Build opening tag
|
|
168
178
|
tag_parts = [f'<{node.tag}']
|
|
@@ -422,44 +432,8 @@ class HTMLRenderer:
|
|
|
422
432
|
return ''
|
|
423
433
|
|
|
424
434
|
def _evaluate_condition(self, condition: str) -> bool:
|
|
425
|
-
"""
|
|
426
|
-
|
|
427
|
-
return False
|
|
428
|
-
|
|
429
|
-
# Evaluate the condition as an expression, without interpolating any
|
|
430
|
-
# values into it first.
|
|
431
|
-
#
|
|
432
|
-
# This used to build a string by substituting databinding results into
|
|
433
|
-
# the condition and then eval() it. That is not a comparison, it is
|
|
434
|
-
# code assembly from data: a record whose name is "'; __import__(...)"
|
|
435
|
-
# became executable code. Stripping the braces instead leaves the
|
|
436
|
-
# variable NAMES in place and lets the evaluator resolve them, so no
|
|
437
|
-
# value is ever parsed as syntax. PUBLIC_RELEASE_PLAN.md P0.1.
|
|
438
|
-
stripped = re.sub(r'\{([^}]+)\}', r'\1', condition).strip()
|
|
439
|
-
try:
|
|
440
|
-
return bool(self._expressions.evaluate(
|
|
441
|
-
stripped, self.context.get_all_variables(), absent_scope_key_is_none=True
|
|
442
|
-
))
|
|
443
|
-
except UndefinedError:
|
|
444
|
-
# EXPR-5: a missing name, key or attribute makes a condition FALSE,
|
|
445
|
-
# not true. Other failures raise (see ComponentRuntime).
|
|
446
|
-
#
|
|
447
|
-
#
|
|
448
|
-
# This used to fall through to _apply_databinding, which hands back
|
|
449
|
-
# the literal placeholder '{session.user.is_admin}' — a non-empty
|
|
450
|
-
# string, which the truthiness rule below then read as True. So
|
|
451
|
-
# <q:if condition="session.user.is_admin">
|
|
452
|
-
# rendered its admin branch for a logged-out visitor whose session
|
|
453
|
-
# had no `user`, and every q:else guarding it never fired. A
|
|
454
|
-
# condition failing open is an authorization bypass by
|
|
455
|
-
# construction. Reported by two audit dimensions, reproduced
|
|
456
|
-
# directly. See tests/integration/test_condition_fails_closed.py.
|
|
457
|
-
report_unresolved(stripped, ExpressionError(
|
|
458
|
-
f"condition {condition!r} could not be evaluated; treated as false"
|
|
459
|
-
))
|
|
460
|
-
return False
|
|
461
|
-
except ExpressionError as exc:
|
|
462
|
-
raise ExpressionError(f"condition {condition!r} could not be evaluated: {exc}") from exc
|
|
435
|
+
"""A condition by the language's rules — see quantum/runtime/conditions.py."""
|
|
436
|
+
return evaluate_condition(self._expressions, condition, self.context.get_all_variables())
|
|
463
437
|
|
|
464
438
|
def _render_comment(self, node: CommentNode) -> str:
|
|
465
439
|
"""
|
|
@@ -44,6 +44,13 @@ class UIBuilder:
|
|
|
44
44
|
Returns:
|
|
45
45
|
Generated source code string.
|
|
46
46
|
"""
|
|
47
|
+
if not isinstance(app, ApplicationNode) or getattr(app, 'app_type', None) != 'ui':
|
|
48
|
+
# UI-0: it used to fail with "'ComponentNode' object has no
|
|
49
|
+
# attribute 'app_id'".
|
|
50
|
+
raise UIBuildError(
|
|
51
|
+
'a UI build needs <q:application type="ui">; this file is a '
|
|
52
|
+
f'<q:{"component" if not isinstance(app, ApplicationNode) else "application"}>. '
|
|
53
|
+
'Wrap the ui:window in <q:application id="MyApp" type="ui">.')
|
|
47
54
|
windows = getattr(app, 'ui_windows', [])
|
|
48
55
|
ui_children = getattr(app, 'ui_children', [])
|
|
49
56
|
title = app.app_id or 'Quantum UI'
|
|
@@ -97,13 +104,11 @@ class UIBuilder:
|
|
|
97
104
|
code = self.build(app, target)
|
|
98
105
|
|
|
99
106
|
if output_path is None:
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
ext = '.py'
|
|
106
|
-
output_path = f"{app.app_id}{ext}"
|
|
107
|
+
# UI-0: one file per target. textual and desktop both wrote
|
|
108
|
+
# <id>.py, so building one erased the other.
|
|
109
|
+
sufixo = {'html': '.html', 'textual': '_console.py', 'desktop': '_desktop.py',
|
|
110
|
+
'mobile': '.js', 'react-native': '.js'}.get(target, '.py')
|
|
111
|
+
output_path = f"{app.app_id}{sufixo}"
|
|
107
112
|
|
|
108
113
|
path = Path(output_path)
|
|
109
114
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
@@ -74,6 +74,9 @@ _KNOWN_KEYS = {
|
|
|
74
74
|
'security': {'secret_key', 'login_url', 'python_scripting', 'max_content_length',
|
|
75
75
|
'xss_protection'},
|
|
76
76
|
'performance': {'cache_templates', 'cache_ttl', 'cache_max_size'},
|
|
77
|
+
'server': {'port', 'host', 'debug', 'reload'},
|
|
78
|
+
'paths': {'components', 'static', 'logs', 'uploads', 'migrations'},
|
|
79
|
+
'logging': {'level', 'format', 'console', 'file', 'filename'},
|
|
77
80
|
}
|
|
78
81
|
|
|
79
82
|
_DATASOURCE_KEYS = {'driver', 'type', 'database', 'host', 'port', 'username', 'user', 'password'}
|
|
@@ -220,11 +223,9 @@ class QuantumWebServer:
|
|
|
220
223
|
|
|
221
224
|
self.parser = QuantumParser()
|
|
222
225
|
self.template_cache: Dict[str, Any] = {} # AST cache
|
|
223
|
-
#
|
|
224
|
-
#
|
|
225
|
-
#
|
|
226
|
-
# q:action failed with "Datasource 'db' is not declared locally" —
|
|
227
|
-
# a form that writes to the database did not work at all.
|
|
226
|
+
# Flash helpers only (read/set the flash in the session). q:action
|
|
227
|
+
# bodies run in a runtime built for each request (ACT-10), never in a
|
|
228
|
+
# shared one.
|
|
228
229
|
self.action_handler = ActionHandler(ComponentRuntime(config=self.config))
|
|
229
230
|
|
|
230
231
|
# Phase F: Application scope (global state shared across all users)
|
|
@@ -620,9 +621,15 @@ class QuantumWebServer:
|
|
|
620
621
|
return self._page_redirect(r, guard_runtime)
|
|
621
622
|
session['quantum_session'] = guard_runtime.execution_context.session_vars
|
|
622
623
|
|
|
623
|
-
# Handle action
|
|
624
|
+
# Handle action — in THIS request's runtime (ACT-10). It
|
|
625
|
+
# used to run in one ComponentRuntime shared by every
|
|
626
|
+
# request and thread, which never registered the page's
|
|
627
|
+
# q:functions: calling one inside an action was a 500.
|
|
628
|
+
# guard_runtime has entered this component with this
|
|
629
|
+
# request's scopes.
|
|
624
630
|
try:
|
|
625
|
-
redirect_url, status_code =
|
|
631
|
+
redirect_url, status_code = ActionHandler(guard_runtime).handle_action(
|
|
632
|
+
action_node, route_params=path_params)
|
|
626
633
|
except PageRedirect as r:
|
|
627
634
|
# q:redirect reached through a q:function or q:loop in the action
|
|
628
635
|
return self._page_redirect(r)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quantum-framework
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.14.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
|
{quantum_framework-0.13.0 → quantum_framework-0.14.0}/quantum_framework.egg-info/SOURCES.txt
RENAMED
|
@@ -73,7 +73,6 @@ quantum/core/features/logging/src/runtime.py
|
|
|
73
73
|
quantum/core/features/loops/src/__init__.py
|
|
74
74
|
quantum/core/features/loops/src/ast_node.py
|
|
75
75
|
quantum/core/features/query/src/__init__.py
|
|
76
|
-
quantum/core/features/query/src/database_service.py
|
|
77
76
|
quantum/core/features/query/src/query_validators.py
|
|
78
77
|
quantum/core/features/state_management/src/__init__.py
|
|
79
78
|
quantum/core/features/state_management/src/ast_node.py
|
|
@@ -165,6 +164,7 @@ quantum/runtime/auth_service.py
|
|
|
165
164
|
quantum/runtime/component.py
|
|
166
165
|
quantum/runtime/component_composer.py
|
|
167
166
|
quantum/runtime/component_resolver.py
|
|
167
|
+
quantum/runtime/conditions.py
|
|
168
168
|
quantum/runtime/database_service.py
|
|
169
169
|
quantum/runtime/email_service.py
|
|
170
170
|
quantum/runtime/error_handler.py
|