quantum-framework 0.18.0__py3-none-any.whl

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 (333) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/admin.py +131 -0
  4. quantum/cli/check.py +223 -0
  5. quantum/cli/commands/__init__.py +15 -0
  6. quantum/cli/commands/build.py +414 -0
  7. quantum/cli/commands/dev.py +185 -0
  8. quantum/cli/commands/docs.py +329 -0
  9. quantum/cli/commands/lint.py +523 -0
  10. quantum/cli/commands/migrate.py +548 -0
  11. quantum/cli/commands/new.py +622 -0
  12. quantum/cli/commands/serve.py +190 -0
  13. quantum/cli/commands/test.py +193 -0
  14. quantum/cli/deploy.py +810 -0
  15. quantum/cli/hot_reload.py +951 -0
  16. quantum/cli/jobs.py +356 -0
  17. quantum/cli/mq.py +582 -0
  18. quantum/cli/pkg.py +390 -0
  19. quantum/cli/runner.py +565 -0
  20. quantum/cli/server_process.py +159 -0
  21. quantum/cli/utils.py +334 -0
  22. quantum/compiler/__init__.py +30 -0
  23. quantum/compiler/base_generator.py +367 -0
  24. quantum/compiler/cli.py +295 -0
  25. quantum/compiler/expression_transformer.py +444 -0
  26. quantum/compiler/javascript/__init__.py +10 -0
  27. quantum/compiler/javascript/generator.py +659 -0
  28. quantum/compiler/optimizer.py +270 -0
  29. quantum/compiler/python/__init__.py +10 -0
  30. quantum/compiler/python/generator.py +883 -0
  31. quantum/compiler/python/runtime.py +863 -0
  32. quantum/compiler/transpiler.py +330 -0
  33. quantum/core/__init__.py +3 -0
  34. quantum/core/ast_nodes.py +2619 -0
  35. quantum/core/config_env.py +54 -0
  36. quantum/core/docs_links.py +8 -0
  37. quantum/core/expression_diagnostics.py +87 -0
  38. quantum/core/expression_stdlib.py +208 -0
  39. quantum/core/expressions.py +677 -0
  40. quantum/core/features/agents/src/__init__.py +30 -0
  41. quantum/core/features/agents/src/ast_node.py +540 -0
  42. quantum/core/features/conditionals/src/__init__.py +8 -0
  43. quantum/core/features/conditionals/src/ast_node.py +68 -0
  44. quantum/core/features/data_import/src/__init__.py +0 -0
  45. quantum/core/features/data_import/src/ast_node.py +292 -0
  46. quantum/core/features/data_import/src/runtime.py +533 -0
  47. quantum/core/features/dump/src/__init__.py +12 -0
  48. quantum/core/features/dump/src/ast_node.py +106 -0
  49. quantum/core/features/dump/src/parser.py +61 -0
  50. quantum/core/features/dump/src/runtime.py +246 -0
  51. quantum/core/features/functions/src/__init__.py +8 -0
  52. quantum/core/features/functions/src/ast_node.py +149 -0
  53. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  54. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  55. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  56. quantum/core/features/invocation/src/__init__.py +0 -0
  57. quantum/core/features/invocation/src/ast_node.py +147 -0
  58. quantum/core/features/invocation/src/runtime.py +332 -0
  59. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  60. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  61. quantum/core/features/knowledge_base/src/parser.py +82 -0
  62. quantum/core/features/logging/src/__init__.py +12 -0
  63. quantum/core/features/logging/src/ast_node.py +111 -0
  64. quantum/core/features/logging/src/parser.py +50 -0
  65. quantum/core/features/logging/src/runtime.py +190 -0
  66. quantum/core/features/loops/src/__init__.py +8 -0
  67. quantum/core/features/loops/src/ast_node.py +60 -0
  68. quantum/core/features/query/src/__init__.py +0 -0
  69. quantum/core/features/query/src/query_validators.py +20 -0
  70. quantum/core/features/state_management/src/__init__.py +11 -0
  71. quantum/core/features/state_management/src/ast_node.py +121 -0
  72. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  73. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  74. quantum/core/features/terminal_engine/src/parser.py +361 -0
  75. quantum/core/features/testing_engine/src/__init__.py +41 -0
  76. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  77. quantum/core/features/testing_engine/src/parser.py +604 -0
  78. quantum/core/features/theming/src/__init__.py +48 -0
  79. quantum/core/features/theming/src/ast_node.py +137 -0
  80. quantum/core/features/theming/src/presets.py +405 -0
  81. quantum/core/features/ui_engine/src/__init__.py +20 -0
  82. quantum/core/features/ui_engine/src/ast_nodes.py +1913 -0
  83. quantum/core/features/ui_engine/src/parser.py +1192 -0
  84. quantum/core/features/websocket/src/__init__.py +24 -0
  85. quantum/core/features/websocket/src/ast_node.py +247 -0
  86. quantum/core/guards.py +53 -0
  87. quantum/core/html_compat.py +299 -0
  88. quantum/core/parser.py +1551 -0
  89. quantum/core/parser_registry.py +213 -0
  90. quantum/core/parsers/__init__.py +76 -0
  91. quantum/core/parsers/ai/__init__.py +12 -0
  92. quantum/core/parsers/ai/agent_parser.py +106 -0
  93. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  94. quantum/core/parsers/ai/llm_parser.py +78 -0
  95. quantum/core/parsers/ai/team_parser.py +88 -0
  96. quantum/core/parsers/base.py +322 -0
  97. quantum/core/parsers/composition/__init__.py +10 -0
  98. quantum/core/parsers/composition/import_parser.py +50 -0
  99. quantum/core/parsers/composition/slot_parser.py +48 -0
  100. quantum/core/parsers/control_flow/__init__.py +11 -0
  101. quantum/core/parsers/control_flow/if_parser.py +71 -0
  102. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  103. quantum/core/parsers/control_flow/set_parser.py +93 -0
  104. quantum/core/parsers/data/__init__.py +12 -0
  105. quantum/core/parsers/data/data_parser.py +229 -0
  106. quantum/core/parsers/data/invoke_parser.py +133 -0
  107. quantum/core/parsers/data/query_parser.py +213 -0
  108. quantum/core/parsers/data/transaction_parser.py +86 -0
  109. quantum/core/parsers/events/__init__.py +9 -0
  110. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  111. quantum/core/parsers/forms/__init__.py +11 -0
  112. quantum/core/parsers/forms/action_parser.py +79 -0
  113. quantum/core/parsers/forms/flash_parser.py +34 -0
  114. quantum/core/parsers/forms/redirect_parser.py +33 -0
  115. quantum/core/parsers/functions/__init__.py +11 -0
  116. quantum/core/parsers/functions/function_parser.py +98 -0
  117. quantum/core/parsers/functions/param_parser.py +73 -0
  118. quantum/core/parsers/functions/return_parser.py +31 -0
  119. quantum/core/parsers/html/__init__.py +10 -0
  120. quantum/core/parsers/html/component_call_parser.py +130 -0
  121. quantum/core/parsers/html/html_parser.py +115 -0
  122. quantum/core/parsers/jobs/__init__.py +11 -0
  123. quantum/core/parsers/jobs/job_parser.py +71 -0
  124. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  125. quantum/core/parsers/jobs/thread_parser.py +57 -0
  126. quantum/core/parsers/messaging/__init__.py +17 -0
  127. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  128. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_parser.py +114 -0
  130. quantum/core/parsers/messaging/queue_parser.py +61 -0
  131. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  132. quantum/core/parsers/routing/__init__.py +9 -0
  133. quantum/core/parsers/routing/route_parser.py +41 -0
  134. quantum/core/parsers/scripting/__init__.py +12 -0
  135. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  136. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  137. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  138. quantum/core/parsers/scripting/python_parser.py +49 -0
  139. quantum/core/parsers/services/__init__.py +12 -0
  140. quantum/core/parsers/services/dump_parser.py +52 -0
  141. quantum/core/parsers/services/file_parser.py +48 -0
  142. quantum/core/parsers/services/log_parser.py +46 -0
  143. quantum/core/parsers/services/mail_parser.py +65 -0
  144. quantum/core/tiers.py +164 -0
  145. quantum/core/xml_lines.py +81 -0
  146. quantum/packages/__init__.py +28 -0
  147. quantum/packages/manager.py +413 -0
  148. quantum/packages/manifest.py +351 -0
  149. quantum/packages/registry.py +399 -0
  150. quantum/packages/resolver.py +336 -0
  151. quantum/plugins/__init__.py +33 -0
  152. quantum/plugins/hooks.py +329 -0
  153. quantum/plugins/loader.py +479 -0
  154. quantum/plugins/manifest.py +336 -0
  155. quantum/plugins/registry.py +371 -0
  156. quantum/runtime/__init__.py +25 -0
  157. quantum/runtime/action_handler.py +532 -0
  158. quantum/runtime/adapters/__init__.py +88 -0
  159. quantum/runtime/adapters/memory_adapter.py +690 -0
  160. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  161. quantum/runtime/adapters/redis_adapter.py +582 -0
  162. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  163. quantum/runtime/agent_service.py +1133 -0
  164. quantum/runtime/ast_cache.py +506 -0
  165. quantum/runtime/auth_service.py +267 -0
  166. quantum/runtime/component.py +1048 -0
  167. quantum/runtime/component_composer.py +133 -0
  168. quantum/runtime/component_resolver.py +174 -0
  169. quantum/runtime/conditions.py +54 -0
  170. quantum/runtime/database_service.py +595 -0
  171. quantum/runtime/db_schema.py +100 -0
  172. quantum/runtime/dev_panel.py +178 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +283 -0
  176. quantum/runtime/executor_registry.py +178 -0
  177. quantum/runtime/executors/__init__.py +71 -0
  178. quantum/runtime/executors/ai/__init__.py +12 -0
  179. quantum/runtime/executors/ai/agent_executor.py +217 -0
  180. quantum/runtime/executors/ai/knowledge_executor.py +114 -0
  181. quantum/runtime/executors/ai/llm_executor.py +153 -0
  182. quantum/runtime/executors/ai/team_executor.py +171 -0
  183. quantum/runtime/executors/base.py +264 -0
  184. quantum/runtime/executors/control_flow/__init__.py +12 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +98 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +308 -0
  187. quantum/runtime/executors/control_flow/redirect_executor.py +43 -0
  188. quantum/runtime/executors/control_flow/set_executor.py +464 -0
  189. quantum/runtime/executors/data/__init__.py +12 -0
  190. quantum/runtime/executors/data/data_executor.py +156 -0
  191. quantum/runtime/executors/data/invoke_executor.py +228 -0
  192. quantum/runtime/executors/data/query_executor.py +290 -0
  193. quantum/runtime/executors/data/transaction_executor.py +91 -0
  194. quantum/runtime/executors/jobs/__init__.py +11 -0
  195. quantum/runtime/executors/jobs/job_executor.py +190 -0
  196. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  197. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  198. quantum/runtime/executors/messaging/__init__.py +17 -0
  199. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  200. quantum/runtime/executors/messaging/message_executor.py +174 -0
  201. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  202. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  203. quantum/runtime/executors/scripting/__init__.py +11 -0
  204. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  205. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  206. quantum/runtime/executors/scripting/python_executor.py +249 -0
  207. quantum/runtime/executors/services/__init__.py +12 -0
  208. quantum/runtime/executors/services/dump_executor.py +72 -0
  209. quantum/runtime/executors/services/file_executor.py +89 -0
  210. quantum/runtime/executors/services/log_executor.py +77 -0
  211. quantum/runtime/executors/services/mail_executor.py +81 -0
  212. quantum/runtime/expression_cache.py +498 -0
  213. quantum/runtime/file_upload_service.py +326 -0
  214. quantum/runtime/function_registry.py +118 -0
  215. quantum/runtime/game_builder.py +166 -0
  216. quantum/runtime/game_code_generator.py +2371 -0
  217. quantum/runtime/game_templates.py +2006 -0
  218. quantum/runtime/godot_code_generator.py +4681 -0
  219. quantum/runtime/godot_templates.py +1449 -0
  220. quantum/runtime/job_executor.py +1599 -0
  221. quantum/runtime/knowledge_service.py +546 -0
  222. quantum/runtime/llm_cache.py +100 -0
  223. quantum/runtime/llm_providers.py +704 -0
  224. quantum/runtime/llm_service.py +287 -0
  225. quantum/runtime/local_server.py +28 -0
  226. quantum/runtime/logging_setup.py +141 -0
  227. quantum/runtime/message_broker.py +364 -0
  228. quantum/runtime/message_queue_service.py +571 -0
  229. quantum/runtime/param_validation.py +218 -0
  230. quantum/runtime/pypy_compat.py +317 -0
  231. quantum/runtime/python_bridge.py +698 -0
  232. quantum/runtime/query_validators.py +304 -0
  233. quantum/runtime/renderer.py +734 -0
  234. quantum/runtime/service_container.py +470 -0
  235. quantum/runtime/table_params.py +163 -0
  236. quantum/runtime/terminal_builder.py +76 -0
  237. quantum/runtime/terminal_code_generator.py +607 -0
  238. quantum/runtime/terminal_templates.py +243 -0
  239. quantum/runtime/testing_builder.py +77 -0
  240. quantum/runtime/testing_code_generator.py +833 -0
  241. quantum/runtime/testing_templates.py +85 -0
  242. quantum/runtime/ui_builder.py +222 -0
  243. quantum/runtime/ui_console.py +405 -0
  244. quantum/runtime/ui_desktop.py +56 -0
  245. quantum/runtime/ui_form_rules.py +193 -0
  246. quantum/runtime/ui_html_adapter.py +2567 -0
  247. quantum/runtime/ui_html_templates.py +2106 -0
  248. quantum/runtime/ui_mobile_adapter.py +1832 -0
  249. quantum/runtime/ui_mobile_templates.py +1003 -0
  250. quantum/runtime/ui_page_renderer.py +392 -0
  251. quantum/runtime/ui_pager.py +73 -0
  252. quantum/runtime/ui_table_edit.py +139 -0
  253. quantum/runtime/ui_textual_adapter.py +1866 -0
  254. quantum/runtime/ui_textual_templates.py +45 -0
  255. quantum/runtime/ui_tokens.py +465 -0
  256. quantum/runtime/ui_validator.py +365 -0
  257. quantum/runtime/ui_view.py +221 -0
  258. quantum/runtime/validators.py +256 -0
  259. quantum/runtime/web_server.py +2131 -0
  260. quantum/runtime/websocket_adapter.py +501 -0
  261. quantum/runtime/websocket_service.py +585 -0
  262. quantum/runtime/websocket_transport.py +289 -0
  263. quantum/runtime/wsgi.py +101 -0
  264. quantum/services.py +109 -0
  265. quantum/utils/__init__.py +1 -0
  266. quantum_admin/__init__.py +4 -0
  267. quantum_admin/assets/quantum-admin-connectors.js +123 -0
  268. quantum_admin/assets/quantum-admin.css +2058 -0
  269. quantum_admin/assets/quantum-source-highlight.js +106 -0
  270. quantum_admin/backend/__init__.py +4 -0
  271. quantum_admin/backend/audit_service.py +346 -0
  272. quantum_admin/backend/auth_service.py +394 -0
  273. quantum_admin/backend/component_discovery.py +766 -0
  274. quantum_admin/backend/config_generator.py +586 -0
  275. quantum_admin/backend/connector_service.py +1016 -0
  276. quantum_admin/backend/crud.py +557 -0
  277. quantum_admin/backend/database.py +226 -0
  278. quantum_admin/backend/db_setup_service.py +193 -0
  279. quantum_admin/backend/deploy_service.py +698 -0
  280. quantum_admin/backend/docker_service.py +422 -0
  281. quantum_admin/backend/environment_service.py +418 -0
  282. quantum_admin/backend/git_service.py +370 -0
  283. quantum_admin/backend/health_service.py +390 -0
  284. quantum_admin/backend/job_service.py +347 -0
  285. quantum_admin/backend/log_service.py +331 -0
  286. quantum_admin/backend/main.py +14426 -0
  287. quantum_admin/backend/models.py +986 -0
  288. quantum_admin/backend/pipeline_service.py +812 -0
  289. quantum_admin/backend/resource_manager.py +1118 -0
  290. quantum_admin/backend/schemas.py +419 -0
  291. quantum_admin/backend/secret_manager.py +277 -0
  292. quantum_admin/backend/settings_service.py +488 -0
  293. quantum_admin/backend/template_service.py +710 -0
  294. quantum_admin/backend/test_execution_service.py +364 -0
  295. quantum_admin/backend/test_generator.py +782 -0
  296. quantum_admin/backend/webhook_service.py +454 -0
  297. quantum_admin/backend/websocket_manager.py +360 -0
  298. quantum_admin/components/admin/_layout/AdminShell.q +121 -0
  299. quantum_admin/components/admin/agents.q +107 -0
  300. quantum_admin/components/admin/app/[name].q +558 -0
  301. quantum_admin/components/admin/applications.q +160 -0
  302. quantum_admin/components/admin/component/[...path].q +205 -0
  303. quantum_admin/components/admin/components.q +59 -0
  304. quantum_admin/components/admin/connectors.q +283 -0
  305. quantum_admin/components/admin/dashboard.q +86 -0
  306. quantum_admin/components/admin/database.q +95 -0
  307. quantum_admin/components/admin/features.q +69 -0
  308. quantum_admin/components/admin/index.q +12 -0
  309. quantum_admin/components/admin/jobs.q +75 -0
  310. quantum_admin/components/admin/login.q +65 -0
  311. quantum_admin/components/admin/logout.q +11 -0
  312. quantum_admin/components/admin/settings.q +174 -0
  313. quantum_admin/components/admin/source.q +45 -0
  314. quantum_admin/components/admin/tests.q +73 -0
  315. quantum_admin/run.py +13 -0
  316. quantum_admin/services/__init__.py +16 -0
  317. quantum_admin/services/_base.py +84 -0
  318. quantum_admin/services/_component_test_generator.py +205 -0
  319. quantum_admin/services/_yaml_editor.py +82 -0
  320. quantum_admin/services/apps.py +330 -0
  321. quantum_admin/services/auth.py +61 -0
  322. quantum_admin/services/components.py +210 -0
  323. quantum_admin/services/connectors.py +164 -0
  324. quantum_admin/services/projects.py +189 -0
  325. quantum_admin/services/repository.py +223 -0
  326. quantum_admin/services/settings.py +150 -0
  327. quantum_admin/services/yaml_import.py +118 -0
  328. quantum_framework-0.18.0.dist-info/METADATA +281 -0
  329. quantum_framework-0.18.0.dist-info/RECORD +333 -0
  330. quantum_framework-0.18.0.dist-info/WHEEL +5 -0
  331. quantum_framework-0.18.0.dist-info/entry_points.txt +2 -0
  332. quantum_framework-0.18.0.dist-info/licenses/LICENSE +21 -0
  333. quantum_framework-0.18.0.dist-info/top_level.txt +2 -0
@@ -0,0 +1,12 @@
1
+ """
2
+ Logging feature for Quantum Language
3
+
4
+ Provides structured logging with multiple severity levels,
5
+ conditional output, and external service integration.
6
+ """
7
+
8
+ from .ast_node import LogNode
9
+ from .parser import parse_log
10
+ from .runtime import LoggingService
11
+
12
+ __all__ = ['LogNode', 'parse_log', 'LoggingService']
@@ -0,0 +1,111 @@
1
+ """
2
+ AST Node for q:log - Structured Logging
3
+ """
4
+
5
+ from typing import Optional
6
+ from quantum.core.ast_nodes import QuantumNode
7
+
8
+
9
+ class LogNode(QuantumNode):
10
+ """
11
+ Represents a <q:log> - Structured logging statement
12
+
13
+ Example:
14
+ <q:log level="info" message="User {userName} logged in" context="{user}" />
15
+ <q:log level="error" message="API failed" when="{!api_result.success}" />
16
+ """
17
+
18
+ VALID_LEVELS = ['trace', 'debug', 'info', 'warning', 'error', 'critical']
19
+
20
+ # Spellings people actually write, mapped to the level they mean. `warn`
21
+ # is what Python's own logging, JavaScript's console and most log
22
+ # libraries call it, and two examples in this repository use it — one of
23
+ # them the only q:websocket example there is, which therefore did not
24
+ # parse. Rejecting a word the whole industry uses is not strictness, it
25
+ # is a papercut.
26
+ LEVEL_ALIASES = {
27
+ 'warn': 'warning',
28
+ 'fatal': 'critical',
29
+ 'err': 'error',
30
+ 'verbose': 'trace',
31
+ }
32
+
33
+ def __init__(
34
+ self,
35
+ level: str,
36
+ message: str,
37
+ context: Optional[str] = None,
38
+ when: Optional[str] = None,
39
+ provider: Optional[str] = None,
40
+ async_mode: bool = True,
41
+ correlation_id: Optional[str] = None
42
+ ):
43
+ """
44
+ Initialize a LogNode
45
+
46
+ Args:
47
+ level: Log severity level (trace, debug, info, warning, error, critical)
48
+ message: Log message with databinding support
49
+ context: Optional structured data (JSON expression)
50
+ when: Optional conditional expression
51
+ provider: Optional output destination (Phase 2)
52
+ async_mode: Async logging mode (Phase 2)
53
+ correlation_id: Optional request tracking ID (Phase 2)
54
+ """
55
+ # Validate level
56
+ if not level:
57
+ raise ValueError("Log requires 'level' attribute")
58
+
59
+ level = self.LEVEL_ALIASES.get(str(level).strip().lower(), level)
60
+
61
+ if level not in self.VALID_LEVELS:
62
+ raise ValueError(
63
+ f"Invalid log level '{level}'. Must be one of: {', '.join(self.VALID_LEVELS)}"
64
+ )
65
+
66
+ # Validate message
67
+ if message is None:
68
+ raise ValueError("Log requires 'message' attribute")
69
+
70
+ self.level = level
71
+ self.message = message
72
+ self.context = context
73
+ self.when = when
74
+ self.provider = provider
75
+ self.async_mode = async_mode
76
+ self.correlation_id = correlation_id
77
+
78
+ def __repr__(self):
79
+ attrs = [f"level={self.level!r}", f"message={self.message!r}"]
80
+ if self.context:
81
+ attrs.append(f"context={self.context!r}")
82
+ if self.when:
83
+ attrs.append(f"when={self.when!r}")
84
+ return f"LogNode({', '.join(attrs)})"
85
+
86
+ def to_dict(self):
87
+ """Convert node to dictionary for debugging/serialization"""
88
+ return {
89
+ "type": "log",
90
+ "level": self.level,
91
+ "message": self.message[:50] + "..." if self.message and len(self.message) > 50 else self.message,
92
+ "context": self.context,
93
+ "when": self.when,
94
+ "provider": self.provider,
95
+ "async": self.async_mode,
96
+ "correlation_id": self.correlation_id
97
+ }
98
+
99
+ def validate(self):
100
+ """Validate the node and return list of errors"""
101
+ errors = []
102
+
103
+ if not self.level:
104
+ errors.append("Log requires 'level' attribute")
105
+ elif self.level not in self.VALID_LEVELS:
106
+ errors.append(f"Invalid log level '{self.level}'. Must be one of: {', '.join(self.VALID_LEVELS)}")
107
+
108
+ if not self.message:
109
+ errors.append("Log requires 'message' attribute")
110
+
111
+ return errors
@@ -0,0 +1,50 @@
1
+ """
2
+ Parser for q:log - Structured Logging
3
+ """
4
+
5
+ import xml.etree.ElementTree as ET
6
+ from typing import Optional
7
+ from .ast_node import LogNode
8
+
9
+
10
+ def parse_log(log_element: ET.Element) -> LogNode:
11
+ """
12
+ Parse a <q:log> element into a LogNode
13
+
14
+ Args:
15
+ log_element: The XML element representing the log statement
16
+
17
+ Returns:
18
+ LogNode instance
19
+
20
+ Raises:
21
+ ValueError: If required attributes are missing or invalid
22
+ """
23
+ # Get required attributes
24
+ level = log_element.get('level')
25
+ message = log_element.get('message')
26
+
27
+ # Get optional attributes
28
+ context = log_element.get('context')
29
+ when = log_element.get('when')
30
+ provider = log_element.get('provider')
31
+ async_mode_str = log_element.get('async', 'true')
32
+ correlation_id = log_element.get('correlation_id')
33
+
34
+ # Parse async mode
35
+ async_mode = async_mode_str.lower() == 'true' if async_mode_str else True
36
+
37
+ # Validate no child elements (q:log should be self-closing)
38
+ if len(log_element) > 0:
39
+ raise ValueError("Log tag must be self-closing")
40
+
41
+ # Create and return LogNode (validation happens in __init__)
42
+ return LogNode(
43
+ level=level,
44
+ message=message,
45
+ context=context,
46
+ when=when,
47
+ provider=provider,
48
+ async_mode=async_mode,
49
+ correlation_id=correlation_id
50
+ )
@@ -0,0 +1,190 @@
1
+ """
2
+ Runtime service for q:log - Structured Logging
3
+ """
4
+
5
+ import logging
6
+ import json
7
+ import os
8
+ from datetime import datetime
9
+ from typing import Any, Dict, Optional
10
+
11
+
12
+ class LoggingService:
13
+ """
14
+ Service to handle structured logging with multiple severity levels
15
+
16
+ Phase 1 Features:
17
+ - Console and file output
18
+ - JSON structured format
19
+ - Multiple log levels
20
+ - Conditional logging
21
+ - Context data
22
+
23
+ Phase 2 Features (TODO):
24
+ - Loguru integration
25
+ - External services (Sentry, Datadog)
26
+ - Async logging
27
+ - Log rotation
28
+ - Correlation IDs
29
+ """
30
+
31
+ # Map Quantum log levels to Python logging levels
32
+ LEVEL_MAP = {
33
+ 'trace': logging.DEBUG - 5, # Custom level below DEBUG
34
+ 'debug': logging.DEBUG,
35
+ 'info': logging.INFO,
36
+ 'warning': logging.WARNING,
37
+ 'error': logging.ERROR,
38
+ 'critical': logging.CRITICAL
39
+ }
40
+
41
+ _instance: Optional['LoggingService'] = None
42
+ _initialized: bool = False
43
+
44
+ def __new__(cls):
45
+ """Singleton pattern to ensure one logger instance"""
46
+ if cls._instance is None:
47
+ cls._instance = super().__new__(cls)
48
+ return cls._instance
49
+
50
+ def __init__(self):
51
+ """Initialize the logging service"""
52
+ if not LoggingService._initialized:
53
+ self._setup_logging()
54
+ LoggingService._initialized = True
55
+
56
+ @classmethod
57
+ def configure_from_external(cls, logger):
58
+ """
59
+ Inject an externally configured logger so q:log tags reuse
60
+ the same handlers without duplication.
61
+
62
+ Called by logging_setup.setup_logging() after configuring
63
+ the 'quantum' root logger.
64
+ """
65
+ instance = cls.__new__(cls)
66
+ instance.logger = logger
67
+ cls._instance = instance
68
+ cls._initialized = True
69
+
70
+ def _setup_logging(self):
71
+ """Setup logging configuration"""
72
+ # Create logger
73
+ self.logger = logging.getLogger('quantum')
74
+ self.logger.setLevel(logging.DEBUG) # Capture all levels
75
+
76
+ # Prevent duplicate handlers
77
+ if self.logger.handlers:
78
+ return
79
+
80
+ # Console handler - formatted output for development
81
+ console_handler = logging.StreamHandler()
82
+ console_handler.setLevel(logging.DEBUG)
83
+ console_formatter = logging.Formatter(
84
+ '%(asctime)s [%(levelname)s] %(message)s',
85
+ datefmt='%Y-%m-%d %H:%M:%S'
86
+ )
87
+ console_handler.setFormatter(console_formatter)
88
+ self.logger.addHandler(console_handler)
89
+
90
+ # File handler - JSON format for production (Phase 1: basic file logging)
91
+ # Phase 2 will add rotation with Loguru
92
+ log_dir = 'logs'
93
+ os.makedirs(log_dir, exist_ok=True)
94
+ log_file = os.path.join(log_dir, f'quantum_{datetime.now().strftime("%Y%m%d")}.log')
95
+
96
+ file_handler = logging.FileHandler(log_file, encoding='utf-8')
97
+ file_handler.setLevel(logging.DEBUG)
98
+ # For now, use same format. Phase 2 will use JSON formatter
99
+ file_handler.setFormatter(console_formatter)
100
+ self.logger.addHandler(file_handler)
101
+
102
+ # Custom TRACE level
103
+ logging.addLevelName(self.LEVEL_MAP['trace'], 'TRACE')
104
+
105
+ def log(
106
+ self,
107
+ level: str,
108
+ message: str,
109
+ context: Optional[Dict[str, Any]] = None,
110
+ correlation_id: Optional[str] = None
111
+ ) -> Dict[str, Any]:
112
+ """
113
+ Write a log entry
114
+
115
+ Args:
116
+ level: Log severity level
117
+ message: Log message (already resolved with databinding)
118
+ context: Optional structured context data
119
+ correlation_id: Optional request tracking ID
120
+
121
+ Returns:
122
+ Result dictionary with success status
123
+ """
124
+ try:
125
+ # Get Python logging level
126
+ py_level = self.LEVEL_MAP.get(level, logging.INFO)
127
+
128
+ # Build log entry
129
+ log_data = {
130
+ 'timestamp': datetime.now().isoformat(),
131
+ 'level': level,
132
+ 'message': message
133
+ }
134
+
135
+ if context:
136
+ log_data['context'] = context
137
+
138
+ if correlation_id:
139
+ log_data['correlation_id'] = correlation_id
140
+
141
+ # Log to Python logger
142
+ # For Phase 1, just log the message. Phase 2 will log full JSON
143
+ extra_info = []
144
+ if context:
145
+ extra_info.append(f"context={json.dumps(context)}")
146
+ if correlation_id:
147
+ extra_info.append(f"correlation_id={correlation_id}")
148
+
149
+ full_message = message
150
+ if extra_info:
151
+ full_message = f"{message} | {' | '.join(extra_info)}"
152
+
153
+ self.logger.log(py_level, full_message)
154
+
155
+ return {
156
+ 'success': True,
157
+ 'timestamp': log_data['timestamp'],
158
+ 'level': level,
159
+ 'message': message,
160
+ 'destination': 'file+console'
161
+ }
162
+
163
+ except Exception as e:
164
+ # Logging should never crash the application
165
+ # Silently capture errors and return failure
166
+ return {
167
+ 'success': False,
168
+ 'error': str(e)
169
+ }
170
+
171
+ def should_log(self, condition: Any) -> bool:
172
+ """
173
+ Evaluate if logging should occur based on 'when' condition
174
+
175
+ Args:
176
+ condition: Evaluated condition value
177
+
178
+ Returns:
179
+ True if should log, False otherwise
180
+ """
181
+ # If no condition, always log
182
+ if condition is None:
183
+ return True
184
+
185
+ # Evaluate boolean condition
186
+ if isinstance(condition, bool):
187
+ return condition
188
+
189
+ # Truthy evaluation for other types
190
+ return bool(condition)
@@ -0,0 +1,8 @@
1
+ """
2
+ Loops Feature (q:loop)
3
+ """
4
+
5
+ from .ast_node import LoopNode
6
+
7
+ __all__ = ['LoopNode']
8
+ __version__ = '1.0.0'
@@ -0,0 +1,60 @@
1
+ """
2
+ AST Node for Loops (q:loop)
3
+ """
4
+
5
+ from typing import Dict, Any, List
6
+
7
+ # Import base class
8
+ import sys
9
+ from pathlib import Path
10
+ from quantum.core.ast_nodes import QuantumNode
11
+
12
+
13
+ class LoopNode(QuantumNode):
14
+ """Represents a <q:loop> with various types"""
15
+
16
+ def __init__(self, loop_type: str, var_name: str):
17
+ self.loop_type = loop_type # range, array, list, object, query, while
18
+ self.var_name = var_name # variable name for current item
19
+ self.index_name = None # optional index variable
20
+ self.items = None # data source expression
21
+ self.condition = None # for while loops
22
+ self.from_value = None # for range loops
23
+ self.to_value = None # for range loops
24
+ self.step_value = 1 # for range loops
25
+ self.delimiter = "," # for list loops
26
+ self.body: List[QuantumNode] = [] # statements inside loop
27
+
28
+ def add_statement(self, statement: QuantumNode):
29
+ self.body.append(statement)
30
+
31
+ def to_dict(self) -> Dict[str, Any]:
32
+ return {
33
+ "type": "loop",
34
+ "loop_type": self.loop_type,
35
+ "var_name": self.var_name,
36
+ "index_name": self.index_name,
37
+ "from_value": self.from_value,
38
+ "to_value": self.to_value,
39
+ "step_value": self.step_value,
40
+ "body_statements": len(self.body)
41
+ }
42
+
43
+ def validate(self) -> List[str]:
44
+ errors = []
45
+ if not self.var_name:
46
+ errors.append("Loop variable name is required")
47
+
48
+ if self.loop_type == 'range':
49
+ if not self.from_value:
50
+ errors.append("Range loop requires 'from' attribute")
51
+ if not self.to_value:
52
+ errors.append("Range loop requires 'to' attribute")
53
+ elif self.loop_type in ['array', 'list', 'object']:
54
+ if not self.items:
55
+ errors.append(f"{self.loop_type.title()} loop requires 'items' attribute")
56
+
57
+ for statement in self.body:
58
+ errors.extend(statement.validate())
59
+
60
+ return errors
File without changes
@@ -0,0 +1,20 @@
1
+ """
2
+ Quantum Query Validators — re-export of the canonical implementation.
3
+
4
+ This module used to hold a full 290-line COPY of QueryValidator. Nothing
5
+ imported it, so it quietly drifted out of step with the module the runtime
6
+ actually uses (quantum/runtime/query_validators.py) — and by the time the
7
+ audit looked, the two copies of a SECURITY validator disagreed with each
8
+ other. A stale duplicate of a validator is worse than no duplicate: whoever
9
+ reads this one believes they are reading what runs.
10
+
11
+ It re-exports instead of copying, so the two cannot diverge again. Import
12
+ from quantum.runtime.query_validators directly in new code.
13
+ """
14
+
15
+ from quantum.runtime.query_validators import ( # noqa: F401
16
+ QueryValidationError,
17
+ QueryValidator,
18
+ )
19
+
20
+ __all__ = ["QueryValidationError", "QueryValidator"]
@@ -0,0 +1,11 @@
1
+ """
2
+ State Management Feature (q:set)
3
+
4
+ Enables declaration and manipulation of component state variables
5
+ with type safety, validation, and scope management.
6
+ """
7
+
8
+ from .ast_node import SetNode
9
+
10
+ __all__ = ['SetNode']
11
+ __version__ = '1.0.0'
@@ -0,0 +1,121 @@
1
+ """
2
+ AST Node for State Management (q:set)
3
+
4
+ This module contains the SetNode class, which represents the <q:set> tag
5
+ for state management in Quantum Language.
6
+ """
7
+
8
+ from typing import Dict, Any, List, Optional
9
+
10
+ # Import base class from parent AST nodes
11
+ import sys
12
+ from pathlib import Path
13
+ from quantum.core.ast_nodes import QuantumNode
14
+
15
+
16
+ class SetNode(QuantumNode):
17
+ """Represents a <q:set> - State Management"""
18
+
19
+ def __init__(self, name: str):
20
+ # Obrigatórios
21
+ self.name = name
22
+
23
+ # Tipo e valor
24
+ self.type = "string"
25
+ self.value = None
26
+ self.default = None
27
+
28
+ # Validação
29
+ self.required = False
30
+ self.nullable = True
31
+ self.validate_rule = None # Renomeado de 'validate' para não conflitar com o método
32
+ self.pattern = None
33
+ self.mask = None
34
+ self.range = None
35
+ self.enum = None
36
+ self.unique = None
37
+ self.min = None
38
+ self.max = None
39
+ self.minlength = None
40
+ self.maxlength = None
41
+
42
+ # Comportamento
43
+ self.scope = "local"
44
+ self.operation = "assign"
45
+ self.step = 1
46
+
47
+ # Para operações em collections
48
+ self.index = None
49
+ self.key = None
50
+ self.source = None
51
+
52
+ def to_dict(self) -> Dict[str, Any]:
53
+ result = {
54
+ "type": "set",
55
+ "name": self.name,
56
+ "value_type": self.type,
57
+ "value": self.value,
58
+ "default": self.default,
59
+ "scope": self.scope,
60
+ "operation": self.operation,
61
+ "required": self.required,
62
+ "nullable": self.nullable,
63
+ "validation": {
64
+ "validate": self.validate_rule,
65
+ "pattern": self.pattern,
66
+ "mask": self.mask,
67
+ "range": self.range,
68
+ "enum": self.enum,
69
+ "unique": self.unique,
70
+ "min": self.min,
71
+ "max": self.max,
72
+ "minlength": self.minlength,
73
+ "maxlength": self.maxlength
74
+ }
75
+ }
76
+ return result
77
+
78
+ def validate(self) -> List[str]:
79
+ errors = []
80
+
81
+ if not self.name:
82
+ errors.append("Set variable name is required")
83
+
84
+ # Validar tipo
85
+ # 'integer' was missing here even though SetExecutor._convert_to_type()
86
+ # already handles it (target_type in ("integer", "number")), and other
87
+ # AST nodes like AgentToolParamNode accept it — this rejected any
88
+ # q:set/q:param using type="integer" (test-query-loop.q,
89
+ # test-query-params.q, and every qg: sprite param in game_engine_2d).
90
+ valid_types = ['string', 'number', 'integer', 'decimal', 'boolean', 'date', 'datetime',
91
+ 'array', 'object', 'json', 'binary', 'null']
92
+ if self.type not in valid_types:
93
+ errors.append(f"Invalid type: {self.type}. Must be one of {valid_types}")
94
+
95
+ # Validar operação
96
+ valid_operations = ['assign', 'increment', 'decrement', 'add', 'multiply',
97
+ 'append', 'prepend', 'remove', 'removeAt', 'clear', 'sort',
98
+ 'reverse', 'unique', 'merge', 'setProperty', 'deleteProperty',
99
+ 'clone', 'uppercase', 'lowercase', 'trim', 'format']
100
+ if self.operation not in valid_operations:
101
+ errors.append(f"Invalid operation: {self.operation}")
102
+
103
+ # Validar valor obrigatório para assign
104
+ if self.operation == "assign" and not self.value and not self.default and self.required:
105
+ errors.append("Set value or default is required when required=true")
106
+
107
+ # Validar enum
108
+ if self.enum and self.value:
109
+ enum_values = [v.strip() for v in self.enum.split(',')]
110
+ if self.value not in enum_values:
111
+ errors.append(f"Value '{self.value}' not in enum: {enum_values}")
112
+
113
+ # Validar minlength/maxlength
114
+ if self.type == "string" and self.value:
115
+ if self.minlength and len(str(self.value)) < int(self.minlength):
116
+ errors.append(f"Value length {len(str(self.value))} is less than minlength {self.minlength}")
117
+ if self.maxlength and len(str(self.value)) > int(self.maxlength):
118
+ errors.append(f"Value length {len(str(self.value))} exceeds maxlength {self.maxlength}")
119
+
120
+ return errors
121
+
@@ -0,0 +1,21 @@
1
+ """
2
+ Terminal Engine - AST nodes and parser for the qt: namespace.
3
+ """
4
+
5
+ from .ast_nodes import (
6
+ ScreenNode, PanelNode, LayoutNode, TableNode, ColumnNode,
7
+ TerminalInputNode, ButtonNode, MenuNode, OptionNode,
8
+ TextNode_Terminal, ProgressNode, TreeNode, TabsNode, TabNode,
9
+ LogNode_Terminal, HeaderNode_Terminal, FooterNode, StatusNode,
10
+ KeybindingNode, TimerNode_Terminal, ServiceNode, CssNode,
11
+ OnEventNode_Terminal, RawCodeNode_Terminal,
12
+ )
13
+
14
+ __all__ = [
15
+ 'ScreenNode', 'PanelNode', 'LayoutNode', 'TableNode', 'ColumnNode',
16
+ 'TerminalInputNode', 'ButtonNode', 'MenuNode', 'OptionNode',
17
+ 'TextNode_Terminal', 'ProgressNode', 'TreeNode', 'TabsNode', 'TabNode',
18
+ 'LogNode_Terminal', 'HeaderNode_Terminal', 'FooterNode', 'StatusNode',
19
+ 'KeybindingNode', 'TimerNode_Terminal', 'ServiceNode', 'CssNode',
20
+ 'OnEventNode_Terminal', 'RawCodeNode_Terminal',
21
+ ]