quantum-framework 0.9.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 (262) hide show
  1. quantum/__init__.py +1 -0
  2. quantum/cli/__init__.py +2 -0
  3. quantum/cli/commands/__init__.py +15 -0
  4. quantum/cli/commands/build.py +417 -0
  5. quantum/cli/commands/dev.py +185 -0
  6. quantum/cli/commands/docs.py +329 -0
  7. quantum/cli/commands/lint.py +523 -0
  8. quantum/cli/commands/migrate.py +527 -0
  9. quantum/cli/commands/new.py +622 -0
  10. quantum/cli/commands/serve.py +190 -0
  11. quantum/cli/commands/test.py +193 -0
  12. quantum/cli/deploy.py +810 -0
  13. quantum/cli/hot_reload.py +951 -0
  14. quantum/cli/jobs.py +356 -0
  15. quantum/cli/mq.py +582 -0
  16. quantum/cli/pkg.py +390 -0
  17. quantum/cli/runner.py +547 -0
  18. quantum/cli/server_process.py +159 -0
  19. quantum/cli/utils.py +334 -0
  20. quantum/compiler/__init__.py +30 -0
  21. quantum/compiler/base_generator.py +367 -0
  22. quantum/compiler/cli.py +295 -0
  23. quantum/compiler/expression_transformer.py +444 -0
  24. quantum/compiler/javascript/__init__.py +10 -0
  25. quantum/compiler/javascript/generator.py +659 -0
  26. quantum/compiler/optimizer.py +270 -0
  27. quantum/compiler/python/__init__.py +10 -0
  28. quantum/compiler/python/generator.py +883 -0
  29. quantum/compiler/python/runtime.py +863 -0
  30. quantum/compiler/transpiler.py +330 -0
  31. quantum/core/__init__.py +3 -0
  32. quantum/core/ast_nodes.py +2611 -0
  33. quantum/core/expression_diagnostics.py +87 -0
  34. quantum/core/expression_stdlib.py +148 -0
  35. quantum/core/expressions.py +591 -0
  36. quantum/core/features/agents/src/__init__.py +30 -0
  37. quantum/core/features/agents/src/ast_node.py +540 -0
  38. quantum/core/features/conditionals/src/__init__.py +8 -0
  39. quantum/core/features/conditionals/src/ast_node.py +68 -0
  40. quantum/core/features/data_fetching/src/__init__.py +21 -0
  41. quantum/core/features/data_fetching/src/ast_node.py +312 -0
  42. quantum/core/features/data_fetching/src/desktop_adapter.py +351 -0
  43. quantum/core/features/data_fetching/src/html_adapter.py +474 -0
  44. quantum/core/features/data_fetching/src/parser.py +225 -0
  45. quantum/core/features/data_import/src/__init__.py +0 -0
  46. quantum/core/features/data_import/src/ast_node.py +291 -0
  47. quantum/core/features/data_import/src/runtime.py +538 -0
  48. quantum/core/features/dump/src/__init__.py +12 -0
  49. quantum/core/features/dump/src/ast_node.py +106 -0
  50. quantum/core/features/dump/src/parser.py +61 -0
  51. quantum/core/features/dump/src/runtime.py +246 -0
  52. quantum/core/features/functions/src/__init__.py +8 -0
  53. quantum/core/features/functions/src/ast_node.py +149 -0
  54. quantum/core/features/game_engine_2d/src/__init__.py +19 -0
  55. quantum/core/features/game_engine_2d/src/ast_nodes.py +1719 -0
  56. quantum/core/features/game_engine_2d/src/parser.py +983 -0
  57. quantum/core/features/invocation/src/__init__.py +0 -0
  58. quantum/core/features/invocation/src/ast_node.py +146 -0
  59. quantum/core/features/invocation/src/runtime.py +327 -0
  60. quantum/core/features/knowledge_base/src/__init__.py +6 -0
  61. quantum/core/features/knowledge_base/src/ast_node.py +113 -0
  62. quantum/core/features/knowledge_base/src/parser.py +82 -0
  63. quantum/core/features/logging/src/__init__.py +12 -0
  64. quantum/core/features/logging/src/ast_node.py +111 -0
  65. quantum/core/features/logging/src/parser.py +50 -0
  66. quantum/core/features/logging/src/runtime.py +190 -0
  67. quantum/core/features/loops/src/__init__.py +8 -0
  68. quantum/core/features/loops/src/ast_node.py +60 -0
  69. quantum/core/features/query/src/__init__.py +0 -0
  70. quantum/core/features/query/src/database_service.py +322 -0
  71. quantum/core/features/query/src/query_validators.py +20 -0
  72. quantum/core/features/state_management/src/__init__.py +11 -0
  73. quantum/core/features/state_management/src/ast_node.py +228 -0
  74. quantum/core/features/terminal_engine/src/__init__.py +21 -0
  75. quantum/core/features/terminal_engine/src/ast_nodes.py +560 -0
  76. quantum/core/features/terminal_engine/src/parser.py +361 -0
  77. quantum/core/features/testing_engine/src/__init__.py +41 -0
  78. quantum/core/features/testing_engine/src/ast_nodes.py +1212 -0
  79. quantum/core/features/testing_engine/src/parser.py +604 -0
  80. quantum/core/features/theming/src/__init__.py +48 -0
  81. quantum/core/features/theming/src/ast_node.py +137 -0
  82. quantum/core/features/theming/src/presets.py +405 -0
  83. quantum/core/features/ui_engine/src/__init__.py +20 -0
  84. quantum/core/features/ui_engine/src/ast_nodes.py +1854 -0
  85. quantum/core/features/ui_engine/src/parser.py +1106 -0
  86. quantum/core/features/websocket/src/__init__.py +24 -0
  87. quantum/core/features/websocket/src/ast_node.py +247 -0
  88. quantum/core/html_compat.py +299 -0
  89. quantum/core/parser.py +1235 -0
  90. quantum/core/parser_registry.py +213 -0
  91. quantum/core/parsers/__init__.py +76 -0
  92. quantum/core/parsers/ai/__init__.py +12 -0
  93. quantum/core/parsers/ai/agent_parser.py +106 -0
  94. quantum/core/parsers/ai/knowledge_parser.py +86 -0
  95. quantum/core/parsers/ai/llm_parser.py +78 -0
  96. quantum/core/parsers/ai/team_parser.py +88 -0
  97. quantum/core/parsers/base.py +322 -0
  98. quantum/core/parsers/composition/__init__.py +10 -0
  99. quantum/core/parsers/composition/import_parser.py +50 -0
  100. quantum/core/parsers/composition/slot_parser.py +48 -0
  101. quantum/core/parsers/control_flow/__init__.py +11 -0
  102. quantum/core/parsers/control_flow/if_parser.py +68 -0
  103. quantum/core/parsers/control_flow/loop_parser.py +105 -0
  104. quantum/core/parsers/control_flow/set_parser.py +89 -0
  105. quantum/core/parsers/data/__init__.py +12 -0
  106. quantum/core/parsers/data/data_parser.py +217 -0
  107. quantum/core/parsers/data/invoke_parser.py +116 -0
  108. quantum/core/parsers/data/query_parser.py +188 -0
  109. quantum/core/parsers/data/transaction_parser.py +77 -0
  110. quantum/core/parsers/events/__init__.py +9 -0
  111. quantum/core/parsers/events/dispatch_event_parser.py +44 -0
  112. quantum/core/parsers/forms/__init__.py +11 -0
  113. quantum/core/parsers/forms/action_parser.py +54 -0
  114. quantum/core/parsers/forms/flash_parser.py +34 -0
  115. quantum/core/parsers/forms/redirect_parser.py +33 -0
  116. quantum/core/parsers/functions/__init__.py +11 -0
  117. quantum/core/parsers/functions/function_parser.py +137 -0
  118. quantum/core/parsers/functions/param_parser.py +66 -0
  119. quantum/core/parsers/functions/return_parser.py +31 -0
  120. quantum/core/parsers/html/__init__.py +10 -0
  121. quantum/core/parsers/html/component_call_parser.py +130 -0
  122. quantum/core/parsers/html/html_parser.py +115 -0
  123. quantum/core/parsers/jobs/__init__.py +11 -0
  124. quantum/core/parsers/jobs/job_parser.py +71 -0
  125. quantum/core/parsers/jobs/schedule_parser.py +62 -0
  126. quantum/core/parsers/jobs/thread_parser.py +57 -0
  127. quantum/core/parsers/messaging/__init__.py +17 -0
  128. quantum/core/parsers/messaging/message_ack_parser.py +30 -0
  129. quantum/core/parsers/messaging/message_nack_parser.py +30 -0
  130. quantum/core/parsers/messaging/message_parser.py +114 -0
  131. quantum/core/parsers/messaging/queue_parser.py +61 -0
  132. quantum/core/parsers/messaging/websocket_parser.py +121 -0
  133. quantum/core/parsers/persistence/__init__.py +9 -0
  134. quantum/core/parsers/persistence/persist_parser.py +64 -0
  135. quantum/core/parsers/routing/__init__.py +9 -0
  136. quantum/core/parsers/routing/route_parser.py +41 -0
  137. quantum/core/parsers/scripting/__init__.py +12 -0
  138. quantum/core/parsers/scripting/pyclass_parser.py +62 -0
  139. quantum/core/parsers/scripting/pydecorator_parser.py +68 -0
  140. quantum/core/parsers/scripting/pyimport_parser.py +52 -0
  141. quantum/core/parsers/scripting/python_parser.py +49 -0
  142. quantum/core/parsers/services/__init__.py +12 -0
  143. quantum/core/parsers/services/dump_parser.py +52 -0
  144. quantum/core/parsers/services/file_parser.py +48 -0
  145. quantum/core/parsers/services/log_parser.py +46 -0
  146. quantum/core/parsers/services/mail_parser.py +65 -0
  147. quantum/core/tiers.py +82 -0
  148. quantum/packages/__init__.py +28 -0
  149. quantum/packages/manager.py +413 -0
  150. quantum/packages/manifest.py +351 -0
  151. quantum/packages/registry.py +399 -0
  152. quantum/packages/resolver.py +336 -0
  153. quantum/plugins/__init__.py +33 -0
  154. quantum/plugins/hooks.py +329 -0
  155. quantum/plugins/loader.py +479 -0
  156. quantum/plugins/manifest.py +336 -0
  157. quantum/plugins/registry.py +371 -0
  158. quantum/runtime/__init__.py +28 -0
  159. quantum/runtime/action_handler.py +443 -0
  160. quantum/runtime/adapters/__init__.py +88 -0
  161. quantum/runtime/adapters/memory_adapter.py +690 -0
  162. quantum/runtime/adapters/rabbitmq_adapter.py +715 -0
  163. quantum/runtime/adapters/redis_adapter.py +582 -0
  164. quantum/runtime/adapters/sqlite_adapter.py +414 -0
  165. quantum/runtime/agent_service.py +1133 -0
  166. quantum/runtime/api_server.py +86 -0
  167. quantum/runtime/ast_cache.py +506 -0
  168. quantum/runtime/auth_service.py +267 -0
  169. quantum/runtime/component.py +990 -0
  170. quantum/runtime/component_composer.py +319 -0
  171. quantum/runtime/component_resolver.py +174 -0
  172. quantum/runtime/database_service.py +598 -0
  173. quantum/runtime/email_service.py +162 -0
  174. quantum/runtime/error_handler.py +295 -0
  175. quantum/runtime/execution_context.py +286 -0
  176. quantum/runtime/executor_registry.py +171 -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 +262 -0
  184. quantum/runtime/executors/control_flow/__init__.py +11 -0
  185. quantum/runtime/executors/control_flow/if_executor.py +93 -0
  186. quantum/runtime/executors/control_flow/loop_executor.py +307 -0
  187. quantum/runtime/executors/control_flow/set_executor.py +412 -0
  188. quantum/runtime/executors/data/__init__.py +12 -0
  189. quantum/runtime/executors/data/data_executor.py +145 -0
  190. quantum/runtime/executors/data/invoke_executor.py +176 -0
  191. quantum/runtime/executors/data/query_executor.py +256 -0
  192. quantum/runtime/executors/data/transaction_executor.py +91 -0
  193. quantum/runtime/executors/jobs/__init__.py +11 -0
  194. quantum/runtime/executors/jobs/job_executor.py +190 -0
  195. quantum/runtime/executors/jobs/schedule_executor.py +132 -0
  196. quantum/runtime/executors/jobs/thread_executor.py +127 -0
  197. quantum/runtime/executors/messaging/__init__.py +17 -0
  198. quantum/runtime/executors/messaging/message_ack_executor.py +51 -0
  199. quantum/runtime/executors/messaging/message_executor.py +174 -0
  200. quantum/runtime/executors/messaging/queue_executor.py +103 -0
  201. quantum/runtime/executors/messaging/websocket_executor.py +197 -0
  202. quantum/runtime/executors/scripting/__init__.py +11 -0
  203. quantum/runtime/executors/scripting/pyclass_executor.py +90 -0
  204. quantum/runtime/executors/scripting/pyimport_executor.py +81 -0
  205. quantum/runtime/executors/scripting/python_executor.py +249 -0
  206. quantum/runtime/executors/services/__init__.py +12 -0
  207. quantum/runtime/executors/services/dump_executor.py +72 -0
  208. quantum/runtime/executors/services/file_executor.py +89 -0
  209. quantum/runtime/executors/services/log_executor.py +77 -0
  210. quantum/runtime/executors/services/mail_executor.py +81 -0
  211. quantum/runtime/expression_cache.py +498 -0
  212. quantum/runtime/file_upload_service.py +326 -0
  213. quantum/runtime/function_registry.py +118 -0
  214. quantum/runtime/game_builder.py +166 -0
  215. quantum/runtime/game_code_generator.py +2371 -0
  216. quantum/runtime/game_templates.py +2006 -0
  217. quantum/runtime/godot_code_generator.py +4681 -0
  218. quantum/runtime/godot_templates.py +1449 -0
  219. quantum/runtime/job_executor.py +1599 -0
  220. quantum/runtime/knowledge_service.py +500 -0
  221. quantum/runtime/llm_cache.py +100 -0
  222. quantum/runtime/llm_providers.py +704 -0
  223. quantum/runtime/llm_service.py +287 -0
  224. quantum/runtime/logging_setup.py +140 -0
  225. quantum/runtime/message_broker.py +364 -0
  226. quantum/runtime/message_queue_service.py +571 -0
  227. quantum/runtime/param_validation.py +184 -0
  228. quantum/runtime/pypy_compat.py +315 -0
  229. quantum/runtime/python_bridge.py +698 -0
  230. quantum/runtime/query_validators.py +304 -0
  231. quantum/runtime/renderer.py +733 -0
  232. quantum/runtime/service_container.py +444 -0
  233. quantum/runtime/terminal_builder.py +76 -0
  234. quantum/runtime/terminal_code_generator.py +607 -0
  235. quantum/runtime/terminal_templates.py +243 -0
  236. quantum/runtime/testing_builder.py +77 -0
  237. quantum/runtime/testing_code_generator.py +833 -0
  238. quantum/runtime/testing_templates.py +85 -0
  239. quantum/runtime/ui_builder.py +188 -0
  240. quantum/runtime/ui_desktop_adapter.py +1730 -0
  241. quantum/runtime/ui_desktop_templates.py +307 -0
  242. quantum/runtime/ui_html_adapter.py +2691 -0
  243. quantum/runtime/ui_html_templates.py +2297 -0
  244. quantum/runtime/ui_mobile_adapter.py +1832 -0
  245. quantum/runtime/ui_mobile_templates.py +1003 -0
  246. quantum/runtime/ui_textual_adapter.py +1866 -0
  247. quantum/runtime/ui_textual_templates.py +45 -0
  248. quantum/runtime/ui_tokens.py +465 -0
  249. quantum/runtime/ui_validator.py +365 -0
  250. quantum/runtime/validators.py +256 -0
  251. quantum/runtime/web_server.py +1766 -0
  252. quantum/runtime/websocket_adapter.py +501 -0
  253. quantum/runtime/websocket_service.py +585 -0
  254. quantum/runtime/websocket_transport.py +289 -0
  255. quantum/runtime/wsgi.py +101 -0
  256. quantum/utils/__init__.py +1 -0
  257. quantum_framework-0.9.0.dist-info/METADATA +244 -0
  258. quantum_framework-0.9.0.dist-info/RECORD +262 -0
  259. quantum_framework-0.9.0.dist-info/WHEEL +5 -0
  260. quantum_framework-0.9.0.dist-info/entry_points.txt +2 -0
  261. quantum_framework-0.9.0.dist-info/licenses/LICENSE +21 -0
  262. quantum_framework-0.9.0.dist-info/top_level.txt +1 -0
@@ -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