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.
Files changed (366) hide show
  1. {quantum_framework-0.13.0/quantum_framework.egg-info → quantum_framework-0.15.0}/PKG-INFO +2 -1
  2. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/pyproject.toml +2 -1
  3. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/migrate.py +15 -3
  4. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/new.py +1 -1
  5. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/deploy.py +1 -1
  6. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/mq.py +2 -2
  7. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/runner.py +10 -0
  8. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/utils.py +1 -1
  9. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/ast_nodes.py +10 -0
  10. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/parser.py +19 -3
  11. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parser.py +31 -9
  12. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/set_parser.py +6 -1
  13. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/invoke_parser.py +6 -1
  14. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/function_parser.py +7 -0
  15. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/param_parser.py +8 -1
  16. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/component.py +31 -53
  17. quantum_framework-0.15.0/quantum/runtime/conditions.py +54 -0
  18. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/if_executor.py +2 -1
  19. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/loop_executor.py +2 -1
  20. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/logging_setup.py +3 -2
  21. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/param_validation.py +34 -2
  22. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/renderer.py +22 -39
  23. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_builder.py +12 -7
  24. quantum_framework-0.15.0/quantum/runtime/ui_console.py +229 -0
  25. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_html_adapter.py +32 -8
  26. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_html_templates.py +54 -0
  27. quantum_framework-0.15.0/quantum/runtime/ui_page_renderer.py +123 -0
  28. quantum_framework-0.15.0/quantum/runtime/ui_view.py +120 -0
  29. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/web_server.py +30 -7
  30. {quantum_framework-0.13.0 → quantum_framework-0.15.0/quantum_framework.egg-info}/PKG-INFO +2 -1
  31. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/SOURCES.txt +4 -1
  32. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/requires.txt +1 -0
  33. quantum_framework-0.13.0/quantum/core/features/query/src/database_service.py +0 -322
  34. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/LICENSE +0 -0
  35. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/README.md +0 -0
  36. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/__init__.py +0 -0
  37. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/__init__.py +0 -0
  38. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/admin.py +0 -0
  39. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/__init__.py +0 -0
  40. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/build.py +0 -0
  41. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/dev.py +0 -0
  42. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/docs.py +0 -0
  43. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/lint.py +0 -0
  44. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/serve.py +0 -0
  45. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/commands/test.py +0 -0
  46. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/hot_reload.py +0 -0
  47. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/jobs.py +0 -0
  48. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/pkg.py +0 -0
  49. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/cli/server_process.py +0 -0
  50. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/__init__.py +0 -0
  51. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/base_generator.py +0 -0
  52. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/cli.py +0 -0
  53. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/expression_transformer.py +0 -0
  54. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/javascript/__init__.py +0 -0
  55. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/javascript/generator.py +0 -0
  56. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/optimizer.py +0 -0
  57. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/python/__init__.py +0 -0
  58. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/python/generator.py +0 -0
  59. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/python/runtime.py +0 -0
  60. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/compiler/transpiler.py +0 -0
  61. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/__init__.py +0 -0
  62. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/ast_nodes.py +0 -0
  63. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/config_env.py +0 -0
  64. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/expression_diagnostics.py +0 -0
  65. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/expression_stdlib.py +0 -0
  66. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/expressions.py +0 -0
  67. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/agents/src/__init__.py +0 -0
  68. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/agents/src/ast_node.py +0 -0
  69. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
  70. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
  71. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/data_import/src/__init__.py +0 -0
  72. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
  73. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/data_import/src/runtime.py +0 -0
  74. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/__init__.py +0 -0
  75. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/ast_node.py +0 -0
  76. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/parser.py +0 -0
  77. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/dump/src/runtime.py +0 -0
  78. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/functions/src/__init__.py +0 -0
  79. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/functions/src/ast_node.py +0 -0
  80. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
  81. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
  82. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
  83. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/invocation/src/__init__.py +0 -0
  84. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
  85. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/invocation/src/runtime.py +0 -0
  86. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
  87. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
  88. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
  89. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/__init__.py +0 -0
  90. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/ast_node.py +0 -0
  91. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/parser.py +0 -0
  92. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/logging/src/runtime.py +0 -0
  93. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/loops/src/__init__.py +0 -0
  94. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/loops/src/ast_node.py +0 -0
  95. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/query/src/__init__.py +0 -0
  96. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/query/src/query_validators.py +0 -0
  97. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/state_management/src/__init__.py +0 -0
  98. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
  99. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
  100. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
  101. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
  102. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
  103. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
  104. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
  105. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/theming/src/__init__.py +0 -0
  106. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/theming/src/ast_node.py +0 -0
  107. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/theming/src/presets.py +0 -0
  108. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
  109. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/websocket/src/__init__.py +0 -0
  110. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
  111. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/guards.py +0 -0
  112. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/html_compat.py +0 -0
  113. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parser_registry.py +0 -0
  114. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/__init__.py +0 -0
  115. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/__init__.py +0 -0
  116. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/agent_parser.py +0 -0
  117. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
  118. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/llm_parser.py +0 -0
  119. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/ai/team_parser.py +0 -0
  120. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/base.py +0 -0
  121. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/composition/__init__.py +0 -0
  122. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/composition/import_parser.py +0 -0
  123. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
  124. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
  125. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/if_parser.py +0 -0
  126. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
  127. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/__init__.py +0 -0
  128. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/data_parser.py +0 -0
  129. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/query_parser.py +0 -0
  130. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/data/transaction_parser.py +0 -0
  131. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/events/__init__.py +0 -0
  132. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
  133. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/__init__.py +0 -0
  134. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/action_parser.py +0 -0
  135. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
  136. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
  137. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/__init__.py +0 -0
  138. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/functions/return_parser.py +0 -0
  139. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/html/__init__.py +0 -0
  140. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
  141. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/html/html_parser.py +0 -0
  142. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/__init__.py +0 -0
  143. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
  144. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
  145. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
  146. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/__init__.py +0 -0
  147. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
  148. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
  149. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
  150. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
  151. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
  152. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/persistence/__init__.py +0 -0
  153. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/persistence/persist_parser.py +0 -0
  154. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/routing/__init__.py +0 -0
  155. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/routing/route_parser.py +0 -0
  156. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/__init__.py +0 -0
  157. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
  158. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
  159. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
  160. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
  161. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/__init__.py +0 -0
  162. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/dump_parser.py +0 -0
  163. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/file_parser.py +0 -0
  164. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/log_parser.py +0 -0
  165. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/parsers/services/mail_parser.py +0 -0
  166. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/core/tiers.py +0 -0
  167. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/__init__.py +0 -0
  168. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/manager.py +0 -0
  169. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/manifest.py +0 -0
  170. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/registry.py +0 -0
  171. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/packages/resolver.py +0 -0
  172. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/__init__.py +0 -0
  173. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/hooks.py +0 -0
  174. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/loader.py +0 -0
  175. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/manifest.py +0 -0
  176. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/plugins/registry.py +0 -0
  177. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/__init__.py +0 -0
  178. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/action_handler.py +0 -0
  179. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/__init__.py +0 -0
  180. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
  181. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
  182. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
  183. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
  184. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/agent_service.py +0 -0
  185. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ast_cache.py +0 -0
  186. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/auth_service.py +0 -0
  187. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/component_composer.py +0 -0
  188. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/component_resolver.py +0 -0
  189. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/database_service.py +0 -0
  190. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/email_service.py +0 -0
  191. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/error_handler.py +0 -0
  192. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/execution_context.py +0 -0
  193. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executor_registry.py +0 -0
  194. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/__init__.py +0 -0
  195. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/__init__.py +0 -0
  196. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/agent_executor.py +0 -0
  197. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
  198. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/llm_executor.py +0 -0
  199. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
  200. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/base.py +0 -0
  201. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/__init__.py +0 -0
  202. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/redirect_executor.py +0 -0
  203. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/control_flow/set_executor.py +0 -0
  204. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/__init__.py +0 -0
  205. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/data_executor.py +0 -0
  206. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/invoke_executor.py +0 -0
  207. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/query_executor.py +0 -0
  208. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
  209. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
  210. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
  211. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
  212. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
  213. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
  214. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
  215. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
  216. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
  217. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
  218. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
  219. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
  220. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
  221. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
  222. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/__init__.py +0 -0
  223. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
  224. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/file_executor.py +0 -0
  225. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/log_executor.py +0 -0
  226. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
  227. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/expression_cache.py +0 -0
  228. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/file_upload_service.py +0 -0
  229. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/function_registry.py +0 -0
  230. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/game_builder.py +0 -0
  231. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/game_code_generator.py +0 -0
  232. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/game_templates.py +0 -0
  233. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/godot_code_generator.py +0 -0
  234. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/godot_templates.py +0 -0
  235. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/job_executor.py +0 -0
  236. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/knowledge_service.py +0 -0
  237. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/llm_cache.py +0 -0
  238. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/llm_providers.py +0 -0
  239. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/llm_service.py +0 -0
  240. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/message_broker.py +0 -0
  241. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/message_queue_service.py +0 -0
  242. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/pypy_compat.py +0 -0
  243. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/python_bridge.py +0 -0
  244. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/query_validators.py +0 -0
  245. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/service_container.py +0 -0
  246. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/terminal_builder.py +0 -0
  247. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/terminal_code_generator.py +0 -0
  248. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/terminal_templates.py +0 -0
  249. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/testing_builder.py +0 -0
  250. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/testing_code_generator.py +0 -0
  251. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/testing_templates.py +0 -0
  252. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_desktop_adapter.py +0 -0
  253. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_desktop_templates.py +0 -0
  254. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
  255. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_mobile_templates.py +0 -0
  256. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_textual_adapter.py +0 -0
  257. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_textual_templates.py +0 -0
  258. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_tokens.py +0 -0
  259. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/ui_validator.py +0 -0
  260. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/validators.py +0 -0
  261. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/websocket_adapter.py +0 -0
  262. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/websocket_service.py +0 -0
  263. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/websocket_transport.py +0 -0
  264. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/runtime/wsgi.py +0 -0
  265. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/services.py +0 -0
  266. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum/utils/__init__.py +0 -0
  267. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/__init__.py +0 -0
  268. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
  269. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/assets/quantum-admin.css +0 -0
  270. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
  271. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/__init__.py +0 -0
  272. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/audit_service.py +0 -0
  273. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/auth_service.py +0 -0
  274. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/component_discovery.py +0 -0
  275. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/config_generator.py +0 -0
  276. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/connector_service.py +0 -0
  277. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/crud.py +0 -0
  278. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/database.py +0 -0
  279. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/db_setup_service.py +0 -0
  280. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/deploy_service.py +0 -0
  281. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/docker_service.py +0 -0
  282. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/environment_service.py +0 -0
  283. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/git_service.py +0 -0
  284. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/health_service.py +0 -0
  285. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/job_service.py +0 -0
  286. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/log_service.py +0 -0
  287. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/main.py +0 -0
  288. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/models.py +0 -0
  289. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/pipeline_service.py +0 -0
  290. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/resource_manager.py +0 -0
  291. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/schemas.py +0 -0
  292. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/secret_manager.py +0 -0
  293. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/settings_service.py +0 -0
  294. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/template_service.py +0 -0
  295. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/test_execution_service.py +0 -0
  296. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/test_generator.py +0 -0
  297. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/webhook_service.py +0 -0
  298. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/backend/websocket_manager.py +0 -0
  299. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/_layout/AdminShell.q +0 -0
  300. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/agents.q +0 -0
  301. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/app/[name].q +0 -0
  302. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/applications.q +0 -0
  303. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/component/[...path].q +0 -0
  304. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/components.q +0 -0
  305. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/connectors.q +0 -0
  306. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/dashboard.q +0 -0
  307. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/database.q +0 -0
  308. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/features.q +0 -0
  309. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/index.q +0 -0
  310. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/jobs.q +0 -0
  311. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/login.q +0 -0
  312. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/logout.q +0 -0
  313. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/settings.q +0 -0
  314. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/source.q +0 -0
  315. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/components/admin/tests.q +0 -0
  316. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/run.py +0 -0
  317. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/__init__.py +0 -0
  318. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/_base.py +0 -0
  319. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/_component_test_generator.py +0 -0
  320. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/_yaml_editor.py +0 -0
  321. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/apps.py +0 -0
  322. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/auth.py +0 -0
  323. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/components.py +0 -0
  324. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/connectors.py +0 -0
  325. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/projects.py +0 -0
  326. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/repository.py +0 -0
  327. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/settings.py +0 -0
  328. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_admin/services/yaml_import.py +0 -0
  329. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
  330. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/entry_points.txt +0 -0
  331. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/quantum_framework.egg-info/top_level.txt +0 -0
  332. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/setup.cfg +0 -0
  333. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_agent.py +0 -0
  334. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_animations.py +0 -0
  335. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ast_cache.py +0 -0
  336. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_cli_commands.py +0 -0
  337. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_component_library.py +0 -0
  338. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_desktop_bridge.py +0 -0
  339. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_expression_cache.py +0 -0
  340. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_form_validation.py +0 -0
  341. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_codegen.py +0 -0
  342. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_e2e.py +0 -0
  343. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_engine.py +0 -0
  344. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_game_parser.py +0 -0
  345. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_godot_codegen.py +0 -0
  346. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_job_executor.py +0 -0
  347. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_llm_providers.py +0 -0
  348. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_message_broker.py +0 -0
  349. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_message_queue.py +0 -0
  350. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_mobile_target.py +0 -0
  351. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_multi_agent.py +0 -0
  352. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_packages.py +0 -0
  353. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_plugins.py +0 -0
  354. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_pypy_compat.py +0 -0
  355. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_python_scripting.py +0 -0
  356. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_state_persistence.py +0 -0
  357. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_terminal_codegen.py +0 -0
  358. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_terminal_parser.py +0 -0
  359. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_testing_codegen.py +0 -0
  360. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_testing_parser.py +0 -0
  361. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_theming.py +0 -0
  362. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_html_adapter.py +0 -0
  363. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_parity.py +0 -0
  364. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_parser.py +0 -0
  365. {quantum_framework-0.13.0 → quantum_framework-0.15.0}/tests/test_ui_textual_adapter.py +0 -0
  366. {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.13.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.13.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 / "migrations"
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__
@@ -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
- raise UIParseError(f"Unknown UI tag: ui:{local_name}")
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
- component.base_path = root.get('basePath')
579
- component.health_endpoint = root.get('health')
580
- component.metrics_provider = root.get('metrics')
581
- component.trace_provider = root.get('trace')
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.children or [])
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
- set_node.mask = self.get_attr(element, 'mask')
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')
@@ -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
- invoke_node.transform = self.get_attr(element, 'transform')
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
 
@@ -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
- """Evaluate a condition string using databinding"""
466
- if not condition:
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
- plain_fmt = '%(asctime)s %(levelname)-8s %(name)s - %(message)s'
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)