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,103 @@
1
+ """
2
+ Queue Executor - Execute q:queue statements
3
+
4
+ Handles queue/exchange management operations.
5
+ """
6
+
7
+ from typing import Any, List, Dict, Type
8
+ from quantum.runtime.executors.base import BaseExecutor, ExecutorError
9
+ from quantum.core.ast_nodes import QueueNode
10
+
11
+
12
+ class QueueExecutor(BaseExecutor):
13
+ """
14
+ Executor for q:queue statements.
15
+
16
+ Supports:
17
+ - Queue declaration
18
+ - Queue purge
19
+ - Queue deletion
20
+ - Queue info retrieval
21
+ - Dead letter queue configuration
22
+ """
23
+
24
+ @property
25
+ def handles(self) -> List[Type]:
26
+ return [QueueNode]
27
+
28
+ def execute(self, node: QueueNode, exec_context) -> Any:
29
+ """
30
+ Execute queue management operation.
31
+
32
+ Args:
33
+ node: QueueNode with queue configuration
34
+ exec_context: Execution context
35
+
36
+ Returns:
37
+ Queue operation result dict
38
+ """
39
+ try:
40
+ context = exec_context.get_all_variables()
41
+
42
+ # Resolve queue name
43
+ queue_name = self.apply_databinding(node.name, context)
44
+
45
+ # Execute based on action
46
+ if node.action == 'declare':
47
+ result = self._execute_declare(node, queue_name, context)
48
+ elif node.action == 'purge':
49
+ result = self._execute_purge(queue_name)
50
+ elif node.action == 'delete':
51
+ result = self._execute_delete(queue_name)
52
+ elif node.action == 'info':
53
+ result = self._execute_info(queue_name)
54
+ else:
55
+ raise ExecutorError(f"Unknown queue action: {node.action}")
56
+
57
+ # Store result
58
+ result_var = node.result if hasattr(node, 'result') and node.result else f"{queue_name}_result"
59
+ exec_context.set_variable(result_var, result, scope="component")
60
+
61
+ return result
62
+
63
+ except Exception as e:
64
+ raise ExecutorError(f"Queue operation error: {e}")
65
+
66
+ def _execute_declare(self, node: QueueNode, queue_name: str, context: Dict[str, Any]) -> Dict:
67
+ """Declare a queue with configuration."""
68
+ # Build queue options
69
+ options = {
70
+ 'durable': getattr(node, 'durable', True),
71
+ 'exclusive': getattr(node, 'exclusive', False),
72
+ 'auto_delete': getattr(node, 'auto_delete', False)
73
+ }
74
+
75
+ # Dead letter queue
76
+ if hasattr(node, 'dead_letter') and node.dead_letter:
77
+ dlq = self.apply_databinding(node.dead_letter, context)
78
+ options['dead_letter_queue'] = dlq
79
+
80
+ # TTL
81
+ if hasattr(node, 'ttl') and node.ttl:
82
+ options['ttl'] = int(node.ttl)
83
+
84
+ # Max length
85
+ if hasattr(node, 'max_length') and node.max_length:
86
+ options['max_length'] = int(node.max_length)
87
+
88
+ return self.services.message_queue.declare_queue(
89
+ name=queue_name,
90
+ **options
91
+ )
92
+
93
+ def _execute_purge(self, queue_name: str) -> Dict:
94
+ """Purge all messages from a queue."""
95
+ return self.services.message_queue.purge_queue(queue_name)
96
+
97
+ def _execute_delete(self, queue_name: str) -> Dict:
98
+ """Delete a queue."""
99
+ return self.services.message_queue.delete_queue(queue_name)
100
+
101
+ def _execute_info(self, queue_name: str) -> Dict:
102
+ """Get queue information."""
103
+ return self.services.message_queue.get_queue_info(queue_name)
@@ -0,0 +1,197 @@
1
+ """
2
+ WebSocket Executor - Execute q:websocket statements
3
+
4
+ Handles WebSocket connection management and messaging.
5
+ """
6
+
7
+ from typing import Any, List, Dict, Type
8
+ from quantum.runtime.executors.base import BaseExecutor, ExecutorError
9
+
10
+ # Import from features module
11
+ try:
12
+ from quantum.core.features.websocket.src.ast_node import (
13
+ WebSocketNode, WebSocketSendNode, WebSocketCloseNode
14
+ )
15
+ except ImportError:
16
+ from quantum.core.features.websocket.src import (
17
+ WebSocketNode, WebSocketSendNode, WebSocketCloseNode
18
+ )
19
+
20
+
21
+ class WebSocketExecutor(BaseExecutor):
22
+ """
23
+ Executor for q:websocket statements.
24
+
25
+ Supports:
26
+ - WebSocket connection creation
27
+ - Auto-connect and reconnection
28
+ - Event handlers (on-connect, on-message, on-error, on-close)
29
+ - Heartbeat/ping-pong
30
+ """
31
+
32
+ @property
33
+ def handles(self) -> List[Type]:
34
+ return [WebSocketNode]
35
+
36
+ def execute(self, node: WebSocketNode, exec_context) -> Any:
37
+ """
38
+ Execute WebSocket connection creation.
39
+
40
+ Args:
41
+ node: WebSocketNode with WebSocket configuration
42
+ exec_context: Execution context
43
+
44
+ Returns:
45
+ WebSocket connection info dict
46
+ """
47
+ try:
48
+ context = exec_context.get_all_variables()
49
+
50
+ # Resolve URL
51
+ url = self.apply_databinding(node.url, context)
52
+
53
+ # register_handler() expects a callable, not a config dict —
54
+ # build a closure per event that runs the handler's AST body
55
+ # with the incoming event payload bound as local variables.
56
+ handlers = {}
57
+ for handler in node.handlers:
58
+ handlers[handler.event] = self._build_event_handler(handler.body)
59
+
60
+ # Handlers first, connection second. Handlers are keyed by
61
+ # connection NAME, so registering them early is safe — and with a
62
+ # real transport, autoConnect opens the socket inside
63
+ # register_connection and fires on-connect immediately. Register
64
+ # after, and that first event is dispatched to nobody.
65
+ for event, handler in handlers.items():
66
+ self.services.websocket.register_handler(node.name, event, handler)
67
+
68
+ # WebSocketService.register_connection() takes (name, url,
69
+ # metadata) — there is no create_connection(). Connection options
70
+ # ride along as metadata; auto_connect there decides whether a
71
+ # socket is actually opened.
72
+ connection = self.services.websocket.register_connection(
73
+ name=node.name,
74
+ url=url,
75
+ metadata={
76
+ 'auto_connect': node.auto_connect,
77
+ 'reconnect': node.reconnect,
78
+ 'reconnect_delay': node.reconnect_delay,
79
+ 'max_reconnects': node.max_reconnects,
80
+ 'heartbeat': node.heartbeat,
81
+ 'protocols': node.protocols.split(',') if node.protocols else [],
82
+ },
83
+ )
84
+
85
+ result = connection.to_dict()
86
+
87
+ # Store connection reference
88
+ exec_context.set_variable(node.name, result, scope="component")
89
+
90
+ return result
91
+
92
+ except Exception as e:
93
+ exec_context.set_variable(node.name, {
94
+ 'connected': False,
95
+ 'error': str(e),
96
+ 'url': node.url
97
+ }, scope="component")
98
+ raise ExecutorError(f"WebSocket creation error: {e}")
99
+
100
+ def _build_event_handler(self, body):
101
+ """Build a callable for WebSocketService.register_handler().
102
+
103
+ The service calls handlers with the event payload dict; that payload
104
+ is bound as local variables so the handler body can reference it.
105
+ """
106
+ def handle_event(event_data=None):
107
+ variables = event_data if isinstance(event_data, dict) else {'event': event_data}
108
+ return self.run_body_in_child_context(body, variables)
109
+
110
+ return handle_event
111
+
112
+
113
+ class WebSocketSendExecutor(BaseExecutor):
114
+ """
115
+ Executor for q:websocket-send statements.
116
+
117
+ Sends messages through an existing WebSocket connection.
118
+ """
119
+
120
+ @property
121
+ def handles(self) -> List[Type]:
122
+ return [WebSocketSendNode]
123
+
124
+ def execute(self, node: WebSocketSendNode, exec_context) -> Any:
125
+ """
126
+ Execute WebSocket message send.
127
+
128
+ Args:
129
+ node: WebSocketSendNode with send configuration
130
+ exec_context: Execution context
131
+
132
+ Returns:
133
+ Send result dict
134
+ """
135
+ try:
136
+ context = exec_context.get_all_variables()
137
+
138
+ # Resolve message
139
+ message = self.apply_databinding(node.message, context)
140
+
141
+ # Get connection
142
+ connection = node.connection
143
+
144
+ # Send message
145
+ sent = self.services.websocket.send_message(
146
+ connection_name=connection,
147
+ data=message,
148
+ msg_type=node.type or 'text',
149
+ )
150
+
151
+ return {'connection': connection, 'sent': sent}
152
+
153
+ except Exception as e:
154
+ raise ExecutorError(f"WebSocket send error: {e}")
155
+
156
+
157
+ class WebSocketCloseExecutor(BaseExecutor):
158
+ """
159
+ Executor for q:websocket-close statements.
160
+
161
+ Closes an existing WebSocket connection.
162
+ """
163
+
164
+ @property
165
+ def handles(self) -> List[Type]:
166
+ return [WebSocketCloseNode]
167
+
168
+ def execute(self, node: WebSocketCloseNode, exec_context) -> Any:
169
+ """
170
+ Execute WebSocket connection close.
171
+
172
+ Args:
173
+ node: WebSocketCloseNode with close configuration
174
+ exec_context: Execution context
175
+
176
+ Returns:
177
+ Close result dict
178
+ """
179
+ try:
180
+ context = exec_context.get_all_variables()
181
+
182
+ # Resolve reason if provided
183
+ reason = ""
184
+ if node.reason:
185
+ reason = self.apply_databinding(node.reason, context)
186
+
187
+ # Close connection
188
+ self.services.websocket.close_connection(
189
+ connection_name=node.connection,
190
+ code=node.code,
191
+ reason=reason,
192
+ )
193
+
194
+ return {'connection': node.connection, 'closed': True, 'code': node.code}
195
+
196
+ except Exception as e:
197
+ raise ExecutorError(f"WebSocket close error: {e}")
@@ -0,0 +1,11 @@
1
+ """
2
+ Scripting Executors
3
+
4
+ Executors for Python scripting: python, pyimport, pyclass.
5
+ """
6
+
7
+ from .python_executor import PythonExecutor
8
+ from .pyimport_executor import PyImportExecutor
9
+ from .pyclass_executor import PyClassExecutor
10
+
11
+ __all__ = ['PythonExecutor', 'PyImportExecutor', 'PyClassExecutor']
@@ -0,0 +1,90 @@
1
+ """
2
+ PyClass Executor - Execute q:class statements
3
+
4
+ Handles inline Python class definitions.
5
+ """
6
+
7
+ from typing import Any, List, Dict, Type
8
+ from quantum.runtime.executors.base import BaseExecutor, ExecutorError
9
+ from quantum.runtime.executors.scripting.python_executor import (
10
+ normalise_python_source,
11
+ )
12
+ from quantum.core.ast_nodes import PyClassNode
13
+
14
+
15
+ class PyClassExecutor(BaseExecutor):
16
+ """
17
+ Executor for q:class statements.
18
+
19
+ Supports:
20
+ - Inline class definition
21
+ - Base class inheritance
22
+ - Decorator application
23
+ """
24
+
25
+ @property
26
+ def handles(self) -> List[Type]:
27
+ return [PyClassNode]
28
+
29
+ def execute(self, node: PyClassNode, exec_context) -> Any:
30
+ """
31
+ Execute Python class definition.
32
+
33
+ Args:
34
+ node: PyClassNode with class configuration
35
+ exec_context: Execution context
36
+
37
+ Returns:
38
+ Defined class
39
+ """
40
+ try:
41
+ self.require_python_scripting('q:pyclass')
42
+
43
+ context = exec_context.get_all_variables()
44
+
45
+ # Build namespace with existing variables
46
+ namespace = dict(context)
47
+
48
+ # Resolve base classes
49
+ bases = []
50
+ for base_name in node.bases:
51
+ if base_name in namespace:
52
+ bases.append(namespace[base_name])
53
+ else:
54
+ # Try to import/eval the base class
55
+ try:
56
+ base = eval(base_name, namespace)
57
+ bases.append(base)
58
+ except:
59
+ raise ExecutorError(f"Base class '{base_name}' not found")
60
+
61
+ if not bases:
62
+ bases = [object]
63
+
64
+ # Build class body. The source is dedented for the same reason
65
+ # q:python's is: markup-indented code raised "unexpected indent"
66
+ # on line 2, which is every class body written inside XML.
67
+ class_body = {}
68
+ exec(normalise_python_source(node.code), namespace, class_body)
69
+
70
+ # Create the class
71
+ cls = type(node.name, tuple(bases), class_body)
72
+
73
+ # Apply decorators (in reverse order)
74
+ for decorator_name in reversed(node.decorators):
75
+ if decorator_name in namespace:
76
+ decorator = namespace[decorator_name]
77
+ else:
78
+ try:
79
+ decorator = eval(decorator_name, namespace)
80
+ except:
81
+ raise ExecutorError(f"Decorator '{decorator_name}' not found")
82
+ cls = decorator(cls)
83
+
84
+ # Store class in context
85
+ exec_context.set_variable(node.name, cls, scope="component")
86
+
87
+ return cls
88
+
89
+ except Exception as e:
90
+ raise ExecutorError(f"PyClass execution error: {e}")
@@ -0,0 +1,81 @@
1
+ """
2
+ PyImport Executor - Execute q:pyimport statements
3
+
4
+ Handles Python module imports.
5
+ """
6
+
7
+ from typing import Any, List, Dict, Type
8
+ from quantum.runtime.executors.base import BaseExecutor, ExecutorError
9
+ from quantum.core.ast_nodes import PyImportNode
10
+
11
+
12
+ class PyImportExecutor(BaseExecutor):
13
+ """
14
+ Executor for q:pyimport statements.
15
+
16
+ Supports:
17
+ - Module import with alias
18
+ - Specific name imports (from X import Y)
19
+ - Star imports (from X import *)
20
+ """
21
+
22
+ @property
23
+ def handles(self) -> List[Type]:
24
+ return [PyImportNode]
25
+
26
+ def execute(self, node: PyImportNode, exec_context) -> Any:
27
+ """
28
+ Execute Python import.
29
+
30
+ Args:
31
+ node: PyImportNode with import configuration
32
+ exec_context: Execution context
33
+
34
+ Returns:
35
+ Imported module or names
36
+ """
37
+ try:
38
+ self.require_python_scripting('q:pyimport')
39
+
40
+ import importlib
41
+
42
+ # Import the module
43
+ module = importlib.import_module(node.module)
44
+
45
+ # Handle different import styles
46
+ if node.alias:
47
+ # import X as Y
48
+ exec_context.set_variable(node.alias, module, scope="component")
49
+ return module
50
+
51
+ elif node.names:
52
+ # from X import Y, Z
53
+ imported = {}
54
+ for name in node.names:
55
+ name = name.strip()
56
+ if name == '*':
57
+ # Import all public names
58
+ for attr_name in dir(module):
59
+ if not attr_name.startswith('_'):
60
+ attr = getattr(module, attr_name)
61
+ exec_context.set_variable(attr_name, attr, scope="component")
62
+ imported[attr_name] = attr
63
+ else:
64
+ attr = getattr(module, name)
65
+ exec_context.set_variable(name, attr, scope="component")
66
+ imported[name] = attr
67
+ return imported
68
+
69
+ else:
70
+ # import X
71
+ # Use last part of module name
72
+ module_name = node.module.split('.')[-1]
73
+ exec_context.set_variable(module_name, module, scope="component")
74
+ return module
75
+
76
+ except ImportError as e:
77
+ raise ExecutorError(f"Import error: Cannot import '{node.module}': {e}")
78
+ except AttributeError as e:
79
+ raise ExecutorError(f"Import error: Module '{node.module}' has no attribute: {e}")
80
+ except Exception as e:
81
+ raise ExecutorError(f"PyImport execution error: {e}")