quantum-framework 0.12.0__tar.gz → 0.13.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 (363) hide show
  1. {quantum_framework-0.12.0/quantum_framework.egg-info → quantum_framework-0.13.0}/PKG-INFO +1 -1
  2. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/pyproject.toml +1 -1
  3. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/migrate.py +31 -3
  4. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/runner.py +4 -0
  5. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/expression_stdlib.py +28 -2
  6. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/expressions.py +69 -4
  7. quantum_framework-0.13.0/quantum/core/guards.py +53 -0
  8. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parser.py +67 -12
  9. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/control_flow/if_parser.py +25 -22
  10. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/forms/action_parser.py +17 -7
  11. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/action_handler.py +8 -2
  12. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/component.py +46 -20
  13. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/database_service.py +32 -40
  14. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/error_handler.py +1 -1
  15. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/execution_context.py +0 -3
  16. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/__init__.py +2 -2
  17. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/base.py +3 -1
  18. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/control_flow/__init__.py +2 -1
  19. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/control_flow/if_executor.py +14 -10
  20. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/control_flow/loop_executor.py +6 -6
  21. quantum_framework-0.13.0/quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  22. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/renderer.py +1 -1
  23. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/web_server.py +128 -47
  24. {quantum_framework-0.12.0 → quantum_framework-0.13.0/quantum_framework.egg-info}/PKG-INFO +1 -1
  25. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_framework.egg-info/SOURCES.txt +2 -1
  26. quantum_framework-0.12.0/tests/test_projects_blog_components_admin.py +0 -514
  27. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/LICENSE +0 -0
  28. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/README.md +0 -0
  29. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/__init__.py +0 -0
  30. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/__init__.py +0 -0
  31. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/admin.py +0 -0
  32. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/__init__.py +0 -0
  33. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/build.py +0 -0
  34. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/dev.py +0 -0
  35. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/docs.py +0 -0
  36. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/lint.py +0 -0
  37. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/new.py +0 -0
  38. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/serve.py +0 -0
  39. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/commands/test.py +0 -0
  40. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/deploy.py +0 -0
  41. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/hot_reload.py +0 -0
  42. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/jobs.py +0 -0
  43. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/mq.py +0 -0
  44. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/pkg.py +0 -0
  45. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/server_process.py +0 -0
  46. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/cli/utils.py +0 -0
  47. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/__init__.py +0 -0
  48. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/base_generator.py +0 -0
  49. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/cli.py +0 -0
  50. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/expression_transformer.py +0 -0
  51. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/javascript/__init__.py +0 -0
  52. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/javascript/generator.py +0 -0
  53. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/optimizer.py +0 -0
  54. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/python/__init__.py +0 -0
  55. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/python/generator.py +0 -0
  56. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/python/runtime.py +0 -0
  57. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/compiler/transpiler.py +0 -0
  58. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/__init__.py +0 -0
  59. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/ast_nodes.py +0 -0
  60. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/config_env.py +0 -0
  61. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/expression_diagnostics.py +0 -0
  62. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/agents/src/__init__.py +0 -0
  63. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/agents/src/ast_node.py +0 -0
  64. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/conditionals/src/__init__.py +0 -0
  65. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/conditionals/src/ast_node.py +0 -0
  66. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/data_import/src/__init__.py +0 -0
  67. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/data_import/src/ast_node.py +0 -0
  68. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/data_import/src/runtime.py +0 -0
  69. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/dump/src/__init__.py +0 -0
  70. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/dump/src/ast_node.py +0 -0
  71. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/dump/src/parser.py +0 -0
  72. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/dump/src/runtime.py +0 -0
  73. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/functions/src/__init__.py +0 -0
  74. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/functions/src/ast_node.py +0 -0
  75. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/game_engine_2d/src/__init__.py +0 -0
  76. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/game_engine_2d/src/ast_nodes.py +0 -0
  77. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/game_engine_2d/src/parser.py +0 -0
  78. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/invocation/src/__init__.py +0 -0
  79. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/invocation/src/ast_node.py +0 -0
  80. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/invocation/src/runtime.py +0 -0
  81. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/knowledge_base/src/__init__.py +0 -0
  82. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/knowledge_base/src/ast_node.py +0 -0
  83. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/knowledge_base/src/parser.py +0 -0
  84. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/logging/src/__init__.py +0 -0
  85. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/logging/src/ast_node.py +0 -0
  86. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/logging/src/parser.py +0 -0
  87. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/logging/src/runtime.py +0 -0
  88. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/loops/src/__init__.py +0 -0
  89. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/loops/src/ast_node.py +0 -0
  90. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/query/src/__init__.py +0 -0
  91. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/query/src/database_service.py +0 -0
  92. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/query/src/query_validators.py +0 -0
  93. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/state_management/src/__init__.py +0 -0
  94. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/state_management/src/ast_node.py +0 -0
  95. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/terminal_engine/src/__init__.py +0 -0
  96. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/terminal_engine/src/ast_nodes.py +0 -0
  97. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/terminal_engine/src/parser.py +0 -0
  98. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/testing_engine/src/__init__.py +0 -0
  99. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/testing_engine/src/ast_nodes.py +0 -0
  100. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/testing_engine/src/parser.py +0 -0
  101. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/theming/src/__init__.py +0 -0
  102. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/theming/src/ast_node.py +0 -0
  103. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/theming/src/presets.py +0 -0
  104. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/ui_engine/src/__init__.py +0 -0
  105. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/ui_engine/src/ast_nodes.py +0 -0
  106. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/ui_engine/src/parser.py +0 -0
  107. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/websocket/src/__init__.py +0 -0
  108. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/features/websocket/src/ast_node.py +0 -0
  109. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/html_compat.py +0 -0
  110. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parser_registry.py +0 -0
  111. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/__init__.py +0 -0
  112. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/ai/__init__.py +0 -0
  113. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/ai/agent_parser.py +0 -0
  114. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/ai/knowledge_parser.py +0 -0
  115. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/ai/llm_parser.py +0 -0
  116. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/ai/team_parser.py +0 -0
  117. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/base.py +0 -0
  118. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/composition/__init__.py +0 -0
  119. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/composition/import_parser.py +0 -0
  120. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/composition/slot_parser.py +0 -0
  121. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/control_flow/__init__.py +0 -0
  122. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/control_flow/loop_parser.py +0 -0
  123. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/control_flow/set_parser.py +0 -0
  124. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/data/__init__.py +0 -0
  125. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/data/data_parser.py +0 -0
  126. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/data/invoke_parser.py +0 -0
  127. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/data/query_parser.py +0 -0
  128. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/data/transaction_parser.py +0 -0
  129. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/events/__init__.py +0 -0
  130. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/events/dispatch_event_parser.py +0 -0
  131. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/forms/__init__.py +0 -0
  132. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/forms/flash_parser.py +0 -0
  133. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/forms/redirect_parser.py +0 -0
  134. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/functions/__init__.py +0 -0
  135. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/functions/function_parser.py +0 -0
  136. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/functions/param_parser.py +0 -0
  137. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/functions/return_parser.py +0 -0
  138. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/html/__init__.py +0 -0
  139. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/html/component_call_parser.py +0 -0
  140. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/html/html_parser.py +0 -0
  141. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/jobs/__init__.py +0 -0
  142. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/jobs/job_parser.py +0 -0
  143. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/jobs/schedule_parser.py +0 -0
  144. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/jobs/thread_parser.py +0 -0
  145. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/messaging/__init__.py +0 -0
  146. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/messaging/message_ack_parser.py +0 -0
  147. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/messaging/message_nack_parser.py +0 -0
  148. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/messaging/message_parser.py +0 -0
  149. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/messaging/queue_parser.py +0 -0
  150. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/messaging/websocket_parser.py +0 -0
  151. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/persistence/__init__.py +0 -0
  152. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/persistence/persist_parser.py +0 -0
  153. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/routing/__init__.py +0 -0
  154. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/routing/route_parser.py +0 -0
  155. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/scripting/__init__.py +0 -0
  156. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/scripting/pyclass_parser.py +0 -0
  157. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/scripting/pydecorator_parser.py +0 -0
  158. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/scripting/pyimport_parser.py +0 -0
  159. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/scripting/python_parser.py +0 -0
  160. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/services/__init__.py +0 -0
  161. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/services/dump_parser.py +0 -0
  162. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/services/file_parser.py +0 -0
  163. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/services/log_parser.py +0 -0
  164. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/parsers/services/mail_parser.py +0 -0
  165. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/core/tiers.py +0 -0
  166. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/packages/__init__.py +0 -0
  167. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/packages/manager.py +0 -0
  168. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/packages/manifest.py +0 -0
  169. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/packages/registry.py +0 -0
  170. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/packages/resolver.py +0 -0
  171. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/plugins/__init__.py +0 -0
  172. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/plugins/hooks.py +0 -0
  173. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/plugins/loader.py +0 -0
  174. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/plugins/manifest.py +0 -0
  175. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/plugins/registry.py +0 -0
  176. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/__init__.py +0 -0
  177. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/adapters/__init__.py +0 -0
  178. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/adapters/memory_adapter.py +0 -0
  179. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/adapters/rabbitmq_adapter.py +0 -0
  180. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/adapters/redis_adapter.py +0 -0
  181. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/adapters/sqlite_adapter.py +0 -0
  182. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/agent_service.py +0 -0
  183. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ast_cache.py +0 -0
  184. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/auth_service.py +0 -0
  185. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/component_composer.py +0 -0
  186. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/component_resolver.py +0 -0
  187. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/email_service.py +0 -0
  188. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executor_registry.py +0 -0
  189. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/ai/__init__.py +0 -0
  190. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/ai/agent_executor.py +0 -0
  191. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/ai/knowledge_executor.py +0 -0
  192. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/ai/llm_executor.py +0 -0
  193. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/ai/team_executor.py +0 -0
  194. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/control_flow/set_executor.py +0 -0
  195. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/data/__init__.py +0 -0
  196. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/data/data_executor.py +0 -0
  197. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/data/invoke_executor.py +0 -0
  198. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/data/query_executor.py +0 -0
  199. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/data/transaction_executor.py +0 -0
  200. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/jobs/__init__.py +0 -0
  201. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/jobs/job_executor.py +0 -0
  202. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/jobs/schedule_executor.py +0 -0
  203. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/jobs/thread_executor.py +0 -0
  204. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/messaging/__init__.py +0 -0
  205. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/messaging/message_ack_executor.py +0 -0
  206. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/messaging/message_executor.py +0 -0
  207. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/messaging/queue_executor.py +0 -0
  208. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/messaging/websocket_executor.py +0 -0
  209. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/scripting/__init__.py +0 -0
  210. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/scripting/pyclass_executor.py +0 -0
  211. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/scripting/pyimport_executor.py +0 -0
  212. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/scripting/python_executor.py +0 -0
  213. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/services/__init__.py +0 -0
  214. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/services/dump_executor.py +0 -0
  215. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/services/file_executor.py +0 -0
  216. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/services/log_executor.py +0 -0
  217. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/executors/services/mail_executor.py +0 -0
  218. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/expression_cache.py +0 -0
  219. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/file_upload_service.py +0 -0
  220. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/function_registry.py +0 -0
  221. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/game_builder.py +0 -0
  222. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/game_code_generator.py +0 -0
  223. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/game_templates.py +0 -0
  224. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/godot_code_generator.py +0 -0
  225. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/godot_templates.py +0 -0
  226. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/job_executor.py +0 -0
  227. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/knowledge_service.py +0 -0
  228. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/llm_cache.py +0 -0
  229. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/llm_providers.py +0 -0
  230. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/llm_service.py +0 -0
  231. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/logging_setup.py +0 -0
  232. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/message_broker.py +0 -0
  233. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/message_queue_service.py +0 -0
  234. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/param_validation.py +0 -0
  235. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/pypy_compat.py +0 -0
  236. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/python_bridge.py +0 -0
  237. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/query_validators.py +0 -0
  238. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/service_container.py +0 -0
  239. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/terminal_builder.py +0 -0
  240. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/terminal_code_generator.py +0 -0
  241. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/terminal_templates.py +0 -0
  242. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/testing_builder.py +0 -0
  243. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/testing_code_generator.py +0 -0
  244. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/testing_templates.py +0 -0
  245. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_builder.py +0 -0
  246. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_desktop_adapter.py +0 -0
  247. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_desktop_templates.py +0 -0
  248. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_html_adapter.py +0 -0
  249. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_html_templates.py +0 -0
  250. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_mobile_adapter.py +0 -0
  251. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_mobile_templates.py +0 -0
  252. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_textual_adapter.py +0 -0
  253. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_textual_templates.py +0 -0
  254. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_tokens.py +0 -0
  255. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/ui_validator.py +0 -0
  256. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/validators.py +0 -0
  257. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/websocket_adapter.py +0 -0
  258. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/websocket_service.py +0 -0
  259. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/websocket_transport.py +0 -0
  260. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/runtime/wsgi.py +0 -0
  261. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/services.py +0 -0
  262. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum/utils/__init__.py +0 -0
  263. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/__init__.py +0 -0
  264. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/assets/quantum-admin-connectors.js +0 -0
  265. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/assets/quantum-admin.css +0 -0
  266. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/assets/quantum-source-highlight.js +0 -0
  267. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/__init__.py +0 -0
  268. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/audit_service.py +0 -0
  269. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/auth_service.py +0 -0
  270. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/component_discovery.py +0 -0
  271. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/config_generator.py +0 -0
  272. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/connector_service.py +0 -0
  273. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/crud.py +0 -0
  274. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/database.py +0 -0
  275. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/db_setup_service.py +0 -0
  276. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/deploy_service.py +0 -0
  277. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/docker_service.py +0 -0
  278. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/environment_service.py +0 -0
  279. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/git_service.py +0 -0
  280. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/health_service.py +0 -0
  281. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/job_service.py +0 -0
  282. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/log_service.py +0 -0
  283. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/main.py +0 -0
  284. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/models.py +0 -0
  285. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/pipeline_service.py +0 -0
  286. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/resource_manager.py +0 -0
  287. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/schemas.py +0 -0
  288. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/secret_manager.py +0 -0
  289. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/settings_service.py +0 -0
  290. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/template_service.py +0 -0
  291. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/test_execution_service.py +0 -0
  292. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/test_generator.py +0 -0
  293. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/webhook_service.py +0 -0
  294. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/backend/websocket_manager.py +0 -0
  295. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/_layout/AdminShell.q +0 -0
  296. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/agents.q +0 -0
  297. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/app/[name].q +0 -0
  298. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/applications.q +0 -0
  299. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/component/[...path].q +0 -0
  300. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/components.q +0 -0
  301. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/connectors.q +0 -0
  302. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/dashboard.q +0 -0
  303. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/database.q +0 -0
  304. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/features.q +0 -0
  305. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/index.q +0 -0
  306. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/jobs.q +0 -0
  307. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/login.q +0 -0
  308. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/logout.q +0 -0
  309. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/settings.q +0 -0
  310. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/source.q +0 -0
  311. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/components/admin/tests.q +0 -0
  312. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/run.py +0 -0
  313. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/__init__.py +0 -0
  314. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/_base.py +0 -0
  315. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/_component_test_generator.py +0 -0
  316. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/_yaml_editor.py +0 -0
  317. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/apps.py +0 -0
  318. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/auth.py +0 -0
  319. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/components.py +0 -0
  320. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/connectors.py +0 -0
  321. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/projects.py +0 -0
  322. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/repository.py +0 -0
  323. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/settings.py +0 -0
  324. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_admin/services/yaml_import.py +0 -0
  325. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_framework.egg-info/dependency_links.txt +0 -0
  326. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_framework.egg-info/entry_points.txt +0 -0
  327. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_framework.egg-info/requires.txt +0 -0
  328. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/quantum_framework.egg-info/top_level.txt +0 -0
  329. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/setup.cfg +0 -0
  330. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_agent.py +0 -0
  331. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_animations.py +0 -0
  332. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_ast_cache.py +0 -0
  333. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_cli_commands.py +0 -0
  334. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_component_library.py +0 -0
  335. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_desktop_bridge.py +0 -0
  336. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_expression_cache.py +0 -0
  337. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_form_validation.py +0 -0
  338. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_game_codegen.py +0 -0
  339. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_game_e2e.py +0 -0
  340. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_game_engine.py +0 -0
  341. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_game_parser.py +0 -0
  342. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_godot_codegen.py +0 -0
  343. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_job_executor.py +0 -0
  344. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_llm_providers.py +0 -0
  345. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_message_broker.py +0 -0
  346. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_message_queue.py +0 -0
  347. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_mobile_target.py +0 -0
  348. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_multi_agent.py +0 -0
  349. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_packages.py +0 -0
  350. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_plugins.py +0 -0
  351. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_pypy_compat.py +0 -0
  352. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_python_scripting.py +0 -0
  353. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_state_persistence.py +0 -0
  354. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_terminal_codegen.py +0 -0
  355. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_terminal_parser.py +0 -0
  356. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_testing_codegen.py +0 -0
  357. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_testing_parser.py +0 -0
  358. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_theming.py +0 -0
  359. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_ui_html_adapter.py +0 -0
  360. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_ui_parity.py +0 -0
  361. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_ui_parser.py +0 -0
  362. {quantum_framework-0.12.0 → quantum_framework-0.13.0}/tests/test_ui_textual_adapter.py +0 -0
  363. {quantum_framework-0.12.0 → quantum_framework-0.13.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.12.0
3
+ Version: 0.13.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
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantum-framework"
7
- version = "0.12.0"
7
+ version = "0.13.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"}
@@ -70,7 +70,9 @@ class DatabaseConnection:
70
70
  if not caminho.is_absolute():
71
71
  caminho = self.project_path / caminho
72
72
  caminho.parent.mkdir(parents=True, exist_ok=True)
73
- self._conn = sqlite3.connect(str(caminho))
73
+ # isolation_level=None: execute_script opens the transaction
74
+ # itself, so a CREATE TABLE is inside it too (DB-8).
75
+ self._conn = sqlite3.connect(str(caminho), isolation_level=None)
74
76
  self._db_type = 'sqlite'
75
77
  logger.info("Migrating datasource %s (SQLite at %s)", nome, caminho)
76
78
  return self._conn
@@ -128,6 +130,32 @@ class DatabaseConnection:
128
130
  cursor.execute(sql)
129
131
  return cursor
130
132
 
133
+ def execute_script(self, sql: str):
134
+ """Run a whole migration file, in one transaction (DB-8).
135
+
136
+ sqlite3's execute() takes ONE statement, so every migration with more
137
+ than one — a table and its index — failed with "You can only execute
138
+ one statement at a time". The statements are split here and run
139
+ inside an explicit BEGIN, which commit()/rollback() close: a failure
140
+ halfway leaves no table behind.
141
+ """
142
+ if self._db_type != 'sqlite':
143
+ return self.execute(sql)
144
+ import sqlite3
145
+ cursor = self._conn.cursor()
146
+ if not self._conn.in_transaction:
147
+ cursor.execute('BEGIN')
148
+ pedaco = ''
149
+ for linha in sql.splitlines(keepends=True):
150
+ pedaco += linha
151
+ if sqlite3.complete_statement(pedaco):
152
+ if pedaco.strip():
153
+ cursor.execute(pedaco)
154
+ pedaco = ''
155
+ if pedaco.strip() and not all(l.strip().startswith('--') or not l.strip() for l in pedaco.splitlines()):
156
+ raise MigrationError(f"incomplete SQL statement at the end: {pedaco.strip()[:80]!r}")
157
+ return cursor
158
+
131
159
  def commit(self):
132
160
  self._conn.commit()
133
161
 
@@ -275,7 +303,7 @@ class MigrationRunner:
275
303
  click.echo(f"Applying {migration.version}: {migration.name}...")
276
304
 
277
305
  # Execute migration SQL
278
- self.db.execute(migration.content)
306
+ self.db.execute_script(migration.content)
279
307
 
280
308
  # Record migration
281
309
  self._record_migration(migration)
@@ -338,7 +366,7 @@ class MigrationRunner:
338
366
  click.echo(f"Rolling back {version}: {migration_info['name']}...")
339
367
 
340
368
  # Execute rollback SQL
341
- self.db.execute(down_file.read_text())
369
+ self.db.execute_script(down_file.read_text())
342
370
 
343
371
  # Remove migration record
344
372
  self._remove_migration_record(version)
@@ -24,6 +24,7 @@ if os.name == 'nt': # Windows
24
24
  from quantum.core.parser import QuantumParser, QuantumParseError
25
25
  from quantum.core.ast_nodes import ComponentNode, ApplicationNode, JobNode
26
26
  from quantum.runtime.component import ComponentRuntime, ComponentExecutionError
27
+ from quantum.runtime.executors.control_flow.redirect_executor import PageRedirect
27
28
  from quantum.runtime.web_server import QuantumWebServer
28
29
 
29
30
  # Import deploy commands (lazy load to avoid import errors if requests not installed)
@@ -166,6 +167,9 @@ class QuantumRunner:
166
167
  except ComponentExecutionError as e:
167
168
  print(f"[ERROR] Execution error: {e}")
168
169
  return 1
170
+ except PageRedirect as r:
171
+ print(f"[REDIRECT] {r.status} {r.url}")
172
+ return 0
169
173
 
170
174
  def _execute_application(self, app: ApplicationNode, debug: bool = False) -> int:
171
175
  """Execute q:application"""
@@ -15,6 +15,9 @@ Functions are looked up by name from expressions, so anything added here
15
15
  becomes language surface. That is the reason to keep it short.
16
16
  """
17
17
 
18
+ import math
19
+ import re
20
+ from decimal import Decimal, ROUND_HALF_UP
18
21
  from datetime import datetime, timedelta
19
22
  from typing import Any, Iterable, Optional
20
23
 
@@ -84,6 +87,13 @@ def _split(v: Any, sep: str = ",") -> list: return str(v).split(sep)
84
87
  def _contains(v: Any, needle: Any) -> bool: return str(needle) in str(v)
85
88
 
86
89
 
90
+ def _slugify(v: Any) -> str:
91
+ """'Olá, Mundo!' -> 'ola-mundo': for URLs made from a title (EXPR-9)."""
92
+ import unicodedata
93
+ texto = unicodedata.normalize('NFKD', str(v)).encode('ascii', 'ignore').decode('ascii')
94
+ return re.sub(r'[^a-z0-9]+', '-', texto.lower()).strip('-')
95
+
96
+
87
97
  # -- collections -----------------------------------------------------------
88
98
 
89
99
  def _len(v: Any) -> int:
@@ -114,8 +124,21 @@ def _sort(v: Iterable, reverse: bool = False) -> list:
114
124
  # -- numbers ---------------------------------------------------------------
115
125
 
116
126
  def _round(v: Any, digits: int = 0) -> Any:
117
- result = round(float(v), int(digits))
118
- return int(result) if digits == 0 else result
127
+ # EXPR-9: half away from zero, as in ColdFusion and spreadsheets. Python's
128
+ # round() is banker's rounding over binary floats: round(2.5) was 2 and
129
+ # round(0.125, 2) was 0.12. Decimal over the number's text avoids both.
130
+ casas = int(digits)
131
+ passo = Decimal(1).scaleb(-casas)
132
+ result = Decimal(str(v)).quantize(passo, rounding=ROUND_HALF_UP)
133
+ return int(result) if casas <= 0 else float(result)
134
+
135
+
136
+ def _ceil(v: Any) -> int:
137
+ return math.ceil(float(v))
138
+
139
+
140
+ def _floor(v: Any) -> int:
141
+ return math.floor(float(v))
119
142
 
120
143
 
121
144
  # -- passwords ---------------------------------------------------------------
@@ -165,6 +188,7 @@ STDLIB = {
165
188
  'replace': _replace,
166
189
  'split': _split,
167
190
  'contains': _contains,
191
+ 'slugify': _slugify,
168
192
  # collections
169
193
  'len': _len,
170
194
  'first': _first,
@@ -173,6 +197,8 @@ STDLIB = {
173
197
  'sort': _sort,
174
198
  # numbers
175
199
  'round': _round,
200
+ 'ceil': _ceil,
201
+ 'floor': _floor,
176
202
  'abs': abs,
177
203
  'min': min,
178
204
  'max': max,
@@ -23,6 +23,7 @@ access, and the whole arithmetic/comparison/call surface is about 15%.
23
23
  """
24
24
 
25
25
  import ast
26
+ import contextvars
26
27
  import math
27
28
  import operator
28
29
  import re
@@ -30,6 +31,11 @@ from typing import Any, Callable, Dict, Optional
30
31
 
31
32
  from quantum.core.expression_stdlib import STDLIB
32
33
 
34
+ # EXPR-8: in a condition, a key a scope does not have (`session.userId`
35
+ # before login) is absent, not a failure — see ExpressionEvaluator.evaluate.
36
+ _SCOPES = ('session', 'application', 'request', 'cookie', 'form', 'query')
37
+ _ABSENT_SCOPE_KEY_IS_NONE = contextvars.ContextVar('absent_scope_key_is_none', default=False)
38
+
33
39
 
34
40
  class ExpressionError(Exception):
35
41
  """Raised when an expression cannot be evaluated."""
@@ -249,6 +255,43 @@ def _normalise_js_operators(source: str) -> str:
249
255
  return ''.join(out)
250
256
 
251
257
 
258
+ # EXPR-10: what a JavaScript habit is called here. `Math.ceil(x)` and
259
+ # `text.split(' ')` are the first things people write; the bare "only named
260
+ # function calls are allowed" did not say what to write instead.
261
+ _JS_EQUIVALENTS = {
262
+ 'Math.ceil': 'ceil(x)', 'Math.floor': 'floor(x)', 'Math.round': 'round(x)',
263
+ 'Math.max': 'max(a, b)', 'Math.min': 'min(a, b)', 'Math.abs': 'abs(x)',
264
+ 'Date.now': 'now()', 'parseInt': 'int(x)', 'parseFloat': 'float(x)',
265
+ 'split': "split(text, ' ')", 'join': "join(items, ', ')", 'toUpperCase': 'upper(text)',
266
+ 'toLowerCase': 'lower(text)', 'trim': 'trim(text)', 'replace': 'replace(text, old, new)',
267
+ 'includes': 'contains(text, part)', 'indexOf': 'contains(text, part)',
268
+ }
269
+
270
+
271
+ def _method_hint(func: ast.AST) -> str:
272
+ if not isinstance(func, ast.Attribute):
273
+ return ""
274
+ base = func.value.id if isinstance(func.value, ast.Name) else None
275
+ chave = f"{base}.{func.attr}" if base in ('Math', 'Date') else func.attr
276
+ if chave in _JS_EQUIVALENTS:
277
+ escrito = chave if '.' in chave else f"x.{func.attr}"
278
+ return f"; write {_JS_EQUIVALENTS[chave]} instead of {escrito}(...)"
279
+ return f"; call functions by name, e.g. {func.attr}(x), not x.{func.attr}()"
280
+
281
+
282
+ def names_read(expression: str) -> set:
283
+ """The root names an expression reads — `user` in `user.name > 1` — not the
284
+ functions it calls. An expression that does not parse reads nothing here;
285
+ evaluating it reports the error."""
286
+ try:
287
+ tree = ast.parse(_normalise_js_operators(expression.strip()), mode='eval')
288
+ except SyntaxError:
289
+ return set()
290
+ chamadas = {id(n.func) for n in ast.walk(tree) if isinstance(n, ast.Call)}
291
+ return {n.id for n in ast.walk(tree)
292
+ if isinstance(n, ast.Name) and id(n) not in chamadas}
293
+
294
+
252
295
  class ExpressionEvaluator:
253
296
  """Evaluates Quantum `{...}` expressions against a variable context."""
254
297
 
@@ -274,8 +317,24 @@ class ExpressionEvaluator:
274
317
 
275
318
  # -- public API --------------------------------------------------------
276
319
 
277
- def evaluate(self, expression: str, context: Dict[str, Any]) -> Any:
278
- """Evaluate an expression, raising ExpressionError on any failure."""
320
+ def evaluate(self, expression: str, context: Dict[str, Any],
321
+ absent_scope_key_is_none: bool = False) -> Any:
322
+ """Evaluate an expression, raising ExpressionError on any failure.
323
+
324
+ absent_scope_key_is_none (conditions, EXPR-8): `session.x` where the
325
+ scope has no `x` reads as None instead of raising. A condition is a
326
+ presence test, and a scope key that is not there yet is the ordinary
327
+ case (a page runs before login) — raising made the WHOLE condition
328
+ false, so `not session.authenticated` was false for a visitor with no
329
+ session and a guard written that way never fired.
330
+ """
331
+ marca = _ABSENT_SCOPE_KEY_IS_NONE.set(absent_scope_key_is_none)
332
+ try:
333
+ return self._evaluate(expression, context)
334
+ finally:
335
+ _ABSENT_SCOPE_KEY_IS_NONE.reset(marca)
336
+
337
+ def _evaluate(self, expression: str, context: Dict[str, Any]) -> Any:
279
338
  if expression is None:
280
339
  raise ExpressionError("expression is None")
281
340
 
@@ -473,6 +532,11 @@ class ExpressionEvaluator:
473
532
  plano = self._dotted_name(node)
474
533
  if plano is not None and plano in ctx:
475
534
  return ctx[plano]
535
+ if (_ABSENT_SCOPE_KEY_IS_NONE.get() and isinstance(node.value, ast.Name)
536
+ and node.value.id in _SCOPES):
537
+ escopo = ctx.get(node.value.id)
538
+ if escopo is None or (isinstance(escopo, dict) and node.attr not in escopo):
539
+ return None
476
540
  return self._attribute(self._eval(node.value, ctx), node.attr)
477
541
 
478
542
  if isinstance(node, ast.Subscript):
@@ -588,7 +652,7 @@ class ExpressionEvaluator:
588
652
 
589
653
  def _call(self, node: ast.Call, ctx: Dict[str, Any]) -> Any:
590
654
  if not isinstance(node.func, ast.Name):
591
- raise ExpressionError("only named function calls are allowed")
655
+ raise ExpressionError("only named function calls are allowed" + _method_hint(node.func))
592
656
  fn = self.functions.get(node.func.id)
593
657
  if fn is None and self.function_resolver is not None:
594
658
  # A q:function declared by the component being executed.
@@ -600,7 +664,8 @@ class ExpressionEvaluator:
600
664
  if fn is None:
601
665
  raise ExpressionError(
602
666
  f"function {node.func.id!r} is not defined"
603
- f"{_suggest(node.func.id, self.functions)}"
667
+ + (f"; write {_JS_EQUIVALENTS[node.func.id]}" if node.func.id in _JS_EQUIVALENTS
668
+ else _suggest(node.func.id, self.functions))
604
669
  )
605
670
  args = [self._eval(a, ctx) for a in node.args]
606
671
  kwargs = {kw.arg: self._eval(kw.value, ctx) for kw in node.keywords}
@@ -0,0 +1,53 @@
1
+ """Page guards (AUTH-6): a q:if at the top of a page whose branch has a q:redirect.
2
+
3
+ <q:if condition="not session.authenticated">
4
+ <q:redirect url="/login" />
5
+ </q:if>
6
+
7
+ A q:action does not run the page's statements, so a guard written like this
8
+ used to protect only the GET — the POST ran the action without a session.
9
+ Guards now run before each action of the page as well as before the render.
10
+ """
11
+
12
+ from typing import List
13
+
14
+ from quantum.core.ast_nodes import RedirectNode
15
+ from quantum.core.features.conditionals.src.ast_node import IfNode
16
+
17
+
18
+ def _branches(node: IfNode) -> List:
19
+ corpo = list(node.if_body)
20
+ for bloco in node.elseif_blocks:
21
+ corpo += list(bloco.get('body', []))
22
+ return corpo + list(node.else_body)
23
+
24
+
25
+ def _has_redirect(nodes) -> bool:
26
+ return any(isinstance(n, RedirectNode) or (isinstance(n, IfNode) and _has_redirect(_branches(n)))
27
+ for n in nodes)
28
+
29
+
30
+ def page_guards(component) -> List[IfNode]:
31
+ """The top-level q:if statements that can redirect, in document order."""
32
+ return [s for s in getattr(component, 'statements', [])
33
+ if isinstance(s, IfNode) and _has_redirect(_branches(s))]
34
+
35
+
36
+ def guard_conditions(node: IfNode) -> List[str]:
37
+ """Every condition a guard evaluates, nested q:if included."""
38
+ condicoes = [node.condition] + [b.get('condition', '') for b in node.elseif_blocks]
39
+ for filho in _branches(node):
40
+ if isinstance(filho, IfNode):
41
+ condicoes += guard_conditions(filho)
42
+ return [c for c in condicoes if c]
43
+
44
+
45
+ def mark_guards(component) -> None:
46
+ """Flag each guard, nested q:if included, so its condition fails closed (AUTH-6)."""
47
+ def marcar(node):
48
+ node.is_guard = True
49
+ for filho in _branches(node):
50
+ if isinstance(filho, IfNode):
51
+ marcar(filho)
52
+ for guarda in page_guards(component):
53
+ marcar(guarda)
@@ -626,9 +626,60 @@ class QuantumParser:
626
626
  self._parse_control_flow_statements(root, component)
627
627
 
628
628
  self._check_statements_in_markup(component)
629
+ self._check_guards(component)
629
630
 
630
631
  return component
631
632
 
633
+ def _check_guards(self, component: ComponentNode) -> None:
634
+ """AUTH-6: a guard of a page with actions reads only what exists before the page runs.
635
+
636
+ Guards also run before each q:action, and an action does not run the
637
+ page's other statements. A guard reading a page variable would find it
638
+ missing there, read the condition as false, and let the action run.
639
+ """
640
+ from quantum.core.guards import guard_conditions, mark_guards, page_guards
641
+ from quantum.core.expressions import names_read
642
+
643
+ mark_guards(component)
644
+ if not any(isinstance(s, ActionNode) for s in component.statements):
645
+ return
646
+ guardas = page_guards(component)
647
+ if not guardas:
648
+ return
649
+
650
+ definidos = {p.name for p in getattr(component, 'params', []) or []}
651
+
652
+ def definir(nodes):
653
+ for node in nodes:
654
+ if isinstance(node, (ActionNode, FunctionNode, HTMLNode, TextNode, CommentNode)):
655
+ continue
656
+ if isinstance(node, IfNode):
657
+ corpo = list(node.if_body) + list(node.else_body)
658
+ for bloco in node.elseif_blocks:
659
+ corpo += list(bloco.get('body', []))
660
+ definir(corpo)
661
+ continue
662
+ if isinstance(node, LoopNode):
663
+ definir(node.body)
664
+ continue
665
+ nome = getattr(node, 'name', None)
666
+ if isinstance(nome, str) and nome and '.' not in nome:
667
+ definidos.update({nome, f'{nome}_result'})
668
+
669
+ definir([s for s in component.statements if not any(s is g for g in guardas)])
670
+
671
+ for guarda in guardas:
672
+ for condicao in guard_conditions(guarda):
673
+ lidos = names_read(re.sub(r'\{([^{}]*)\}', r'\1', condicao)) & definidos
674
+ if lidos:
675
+ nome = sorted(lidos)[0]
676
+ raise QuantumParseError(
677
+ f'<q:if condition="{condicao}"> in <q:component name="{component.name}"> '
678
+ f'redirects, so it also runs before the page\'s q:action — where the page '
679
+ f'has not run and {{{nome}}} does not exist, and the guard would let the '
680
+ f'action through. Read the scope directly (e.g. session.x), or protect the '
681
+ f'page with require_auth / require_role.')
682
+
632
683
  # Nodes the HTML renderer draws. Anything else inside markup is a statement,
633
684
  # and statements run in the execution pass, before the render pass sees
634
685
  # the markup around them.
@@ -769,20 +820,13 @@ class QuantumParser:
769
820
 
770
821
  def _attach_else_sibling(self, if_node: 'IfNode', kind: str, element: ET.Element):
771
822
  """Anexa um else/elseif IRMAO ao IfNode anterior — mesmo resultado da
772
- forma aninhada que o IfParser ja monta."""
823
+ forma aninhada que o IfParser ja monta, texto incluido (IF-3)."""
824
+ corpo = self._parser_registry.get_parser('if')._body(element)
773
825
  if kind == 'elseif':
774
- condicao = element.get('condition', '')
775
- corpo = []
776
- for filho in element:
777
- stmt = self._parse_statement(filho)
778
- if stmt:
779
- corpo.append(stmt)
780
- if_node.add_elseif_block(condicao, corpo)
826
+ if_node.add_elseif_block(element.get('condition', ''), corpo)
781
827
  else:
782
- for filho in element:
783
- stmt = self._parse_statement(filho)
784
- if stmt:
785
- if_node.add_else_statement(stmt)
828
+ for stmt in corpo:
829
+ if_node.add_else_statement(stmt)
786
830
 
787
831
  def _parse_statement(self, element: ET.Element) -> Optional[QuantumNode]:
788
832
  """Parse individual statement (return, set, dispatchEvent, etc)"""
@@ -791,6 +835,17 @@ class QuantumParser:
791
835
  # === MODULAR PARSER REGISTRY (no fallback) ===
792
836
  # PHASE 1 DIAGNOSTIC: Legacy fallback disabled to test modular coverage
793
837
  if self._use_modular_parsers and self._parser_registry:
838
+ # PARSE-1: <q:html>, <q:div> — an HTML element name in the q:
839
+ # namespace. The registry answered for it with the HTML parser, so
840
+ # <q:html value="{post.content}"/> became an empty <html> element
841
+ # instead of an unknown tag.
842
+ # q:script is a Quantum tag on purpose: client JavaScript, kept as
843
+ # an HTML node (see ui_desktop_adapter).
844
+ if (self._is_quantum_tag(element) and element_type != 'script'
845
+ and element_type in self._parser_registry.html_parser.tag_names):
846
+ raise QuantumParseError(
847
+ f"<q:{element_type}> is not a Quantum tag: HTML elements are written "
848
+ f"without the q: prefix (<{element_type}>)")
794
849
  if self._parser_registry.has_parser(element_type):
795
850
  return self._parser_registry.parse(element, element_type)
796
851
 
@@ -8,6 +8,7 @@ from typing import List
8
8
  from xml.etree import ElementTree as ET
9
9
  from quantum.core.parsers.base import BaseTagParser
10
10
  from quantum.core.features.conditionals.src.ast_node import IfNode
11
+ from quantum.core.ast_nodes import TextNode
11
12
 
12
13
 
13
14
  class IfParser(BaseTagParser):
@@ -37,32 +38,34 @@ class IfParser(BaseTagParser):
37
38
  condition = self.get_attr(element, 'condition', '')
38
39
  if_node = IfNode(condition)
39
40
 
41
+ # IF-3: text directly in a branch is content, like in q:loop and in an
42
+ # HTML element. Only child elements were read, so
43
+ # <h2><q:if condition="tag">Posts tagged {tag}</q:if></h2> rendered
44
+ # an empty heading.
45
+ principal = self._body(element, skip=('elseif', 'else'))
46
+ for statement in principal:
47
+ if_node.add_if_statement(statement)
48
+
40
49
  for child in element:
41
50
  child_type = self.get_element_name(child)
42
-
43
51
  if child_type == 'elseif':
44
- # Parse elseif block
45
- elseif_condition = self.get_attr(child, 'condition', '')
46
- elseif_body = []
47
-
48
- for elseif_child in child:
49
- statement = self.parse_statement(elseif_child)
50
- if statement:
51
- elseif_body.append(statement)
52
-
53
- if_node.add_elseif_block(elseif_condition, elseif_body)
54
-
52
+ if_node.add_elseif_block(self.get_attr(child, 'condition', ''), self._body(child))
55
53
  elif child_type == 'else':
56
- # Parse else block
57
- for else_child in child:
58
- statement = self.parse_statement(else_child)
59
- if statement:
60
- if_node.add_else_statement(statement)
54
+ for statement in self._body(child):
55
+ if_node.add_else_statement(statement)
61
56
 
62
- else:
63
- # Main if block statement
57
+ return if_node
58
+
59
+ def _body(self, element: ET.Element, skip=()) -> list:
60
+ """The statements and text of a branch, in document order."""
61
+ corpo = []
62
+ if element.text and element.text.strip():
63
+ corpo.append(TextNode(element.text))
64
+ for child in element:
65
+ if self.get_element_name(child) not in skip:
64
66
  statement = self.parse_statement(child)
65
67
  if statement:
66
- if_node.add_if_statement(statement)
67
-
68
- return if_node
68
+ corpo.append(statement)
69
+ if child.tail and child.tail.strip():
70
+ corpo.append(TextNode(child.tail))
71
+ return corpo
@@ -8,6 +8,14 @@ from quantum.core.parsers.base import BaseTagParser
8
8
  from quantum.core.ast_nodes import ActionNode
9
9
 
10
10
 
11
+ _NEVER_ENFORCED = {
12
+ 'require_auth': 'Protect the page with require_auth / require_role on the '
13
+ 'q:component: that covers its actions too (AUTH-1, AUTH-6).',
14
+ 'csrf': 'There is no CSRF token; the session cookie is SameSite=Lax (AUTH-5).',
15
+ 'rate_limit': 'Nothing limits requests; put a reverse proxy in front for that.',
16
+ }
17
+
18
+
11
19
  class ActionParser(BaseTagParser):
12
20
  """
13
21
  Parser for q:action statements.
@@ -30,13 +38,15 @@ class ActionParser(BaseTagParser):
30
38
  method = element.get('method', 'POST')
31
39
  action_node = ActionNode(name, method)
32
40
 
33
- # Parse optional attributes
34
- if element.get('csrf') == 'false':
35
- action_node.validate_csrf = False
36
- if element.get('rate_limit'):
37
- action_node.rate_limit = element.get('rate_limit')
38
- if element.get('require_auth') == 'true':
39
- action_node.require_auth = True
41
+ # AUTH-7: attributes that were parsed and never enforced. The worst
42
+ # is require_auth="true": the action ran for anyone, while the page
43
+ # read as protected. The docs promised csrf= and rate_limit= too.
44
+ for attr, porque in _NEVER_ENFORCED.items():
45
+ if element.get(attr) is not None:
46
+ from quantum.core.parser import QuantumParseError
47
+ raise QuantumParseError(
48
+ f'<q:action name="{name}"> {attr}= is not supported: it was accepted '
49
+ f'and never enforced. {porque}')
40
50
 
41
51
  # Parse children (params, statements)
42
52
  for child in element:
@@ -139,13 +139,19 @@ class ActionHandler:
139
139
  # nothing — the failure existed only as a flash message the user
140
140
  # might never see. Whoever is debugging gets the action name, the
141
141
  # exception and the stack.
142
+ # ACT-9: the most common failure. The action runs without the
143
+ # page's statements, so a variable the page sets is not here.
144
+ mensagem = str(e)
145
+ if 'is not defined' in mensagem:
146
+ mensagem += (". A q:action does not run the page's statements: "
147
+ "query or compute what it needs inside the action")
142
148
  logger.exception(
143
- "q:action %r failed: %s", getattr(action, 'name', '?'), e
149
+ "q:action %r failed: %s", getattr(action, 'name', '?'), mensagem
144
150
  )
145
151
  if owns_context:
146
152
  session['quantum_session'] = context.session_vars
147
153
  session.modified = True
148
- self._set_flash_message(f'Action error: {str(e)}', 'error')
154
+ self._set_flash_message(f'Action error: {mensagem}', 'error')
149
155
  return None, 500
150
156
 
151
157
  def _extract_form_data(self) -> Dict[str, Any]: