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,9 @@
1
+ """
2
+ Persistence Parsers
3
+
4
+ Parsers for persistence-related tags: persist
5
+ """
6
+
7
+ from .persist_parser import PersistParser
8
+
9
+ __all__ = ['PersistParser']
@@ -0,0 +1,64 @@
1
+ """
2
+ Persist Parser - Parse q:persist statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import PersistNode
9
+
10
+
11
+ class PersistParser(BaseTagParser):
12
+ """
13
+ Parser for q:persist statements for explicit persistence configuration.
14
+
15
+ Examples:
16
+ <q:persist scope="local" prefix="myapp_">
17
+ <q:var name="theme" />
18
+ <q:var name="locale" />
19
+ </q:persist>
20
+
21
+ <q:persist scope="sync" key="user_prefs" encrypt="true">
22
+ <q:var name="darkMode" />
23
+ <q:var name="fontSize" />
24
+ </q:persist>
25
+ """
26
+
27
+ @property
28
+ def tag_names(self) -> List[str]:
29
+ return ['persist']
30
+
31
+ def parse(self, element: ET.Element) -> PersistNode:
32
+ """Parse q:persist element"""
33
+ scope = element.get('scope', 'local')
34
+ prefix = element.get('prefix')
35
+ key = element.get('key')
36
+ encrypt = element.get('encrypt', 'false').lower() == 'true'
37
+ storage = element.get('storage')
38
+
39
+ ttl = None
40
+ ttl_attr = element.get('ttl')
41
+ if ttl_attr:
42
+ try:
43
+ ttl = int(ttl_attr)
44
+ except ValueError:
45
+ pass
46
+
47
+ persist_node = PersistNode(
48
+ scope=scope,
49
+ prefix=prefix,
50
+ key=key,
51
+ encrypt=encrypt,
52
+ ttl=ttl,
53
+ storage=storage
54
+ )
55
+
56
+ # Parse q:var children
57
+ for child in element:
58
+ child_type = self._get_element_name(child)
59
+ if child_type == 'var':
60
+ var_name = child.get('name')
61
+ if var_name:
62
+ persist_node.add_variable(var_name)
63
+
64
+ return persist_node
@@ -0,0 +1,9 @@
1
+ """
2
+ Routing Parsers
3
+
4
+ Parsers for routing-related tags: route
5
+ """
6
+
7
+ from .route_parser import RouteParser
8
+
9
+ __all__ = ['RouteParser']
@@ -0,0 +1,41 @@
1
+ """
2
+ Route Parser - Parse q:route statements
3
+ """
4
+
5
+ from typing import List
6
+ from xml.etree import ElementTree as ET
7
+ from quantum.core.parsers.base import BaseTagParser
8
+ from quantum.core.ast_nodes import QuantumRoute
9
+
10
+
11
+ class RouteParser(BaseTagParser):
12
+ """
13
+ Parser for q:route statements.
14
+
15
+ Examples:
16
+ <q:route path="/users" method="GET" />
17
+ <q:route path="/api/products/{id}" method="POST">
18
+ <q:return name="product" type="object" />
19
+ </q:route>
20
+ """
21
+
22
+ @property
23
+ def tag_names(self) -> List[str]:
24
+ return ['route']
25
+
26
+ def parse(self, element: ET.Element) -> QuantumRoute:
27
+ """Parse q:route element"""
28
+ path = element.get('path', '/')
29
+ method = element.get('method', 'GET').upper()
30
+
31
+ route = QuantumRoute(path, method)
32
+
33
+ # Parse q:return inside the route
34
+ for child in element:
35
+ child_type = self._get_element_name(child)
36
+ if child_type == 'return':
37
+ return_node = self.parse_child(child)
38
+ if return_node:
39
+ route.returns.append(return_node)
40
+
41
+ return route
@@ -0,0 +1,12 @@
1
+ """
2
+ Scripting Parsers
3
+
4
+ Parsers for Python scripting: python, pyimport, pyclass, pydecorator.
5
+ """
6
+
7
+ from .python_parser import PythonParser
8
+ from .pyimport_parser import PyImportParser
9
+ from .pyclass_parser import PyClassParser
10
+ from .pydecorator_parser import PyDecoratorParser
11
+
12
+ __all__ = ['PythonParser', 'PyImportParser', 'PyClassParser', 'PyDecoratorParser']
@@ -0,0 +1,62 @@
1
+ """
2
+ PyClass Parser - Parse q:class statements
3
+
4
+ Handles inline Python class definitions.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import PyClassNode
11
+
12
+
13
+ class PyClassParser(BaseTagParser):
14
+ """
15
+ Parser for q:class statements.
16
+
17
+ Supports:
18
+ - Class definition
19
+ - Base class inheritance
20
+ - Decorator application
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['class', 'pyclass']
26
+
27
+ def parse(self, element: ET.Element) -> PyClassNode:
28
+ """
29
+ Parse q:class statement.
30
+
31
+ Args:
32
+ element: XML element for q:class
33
+
34
+ Returns:
35
+ PyClassNode AST node
36
+ """
37
+ name = self.get_attr(element, 'name')
38
+ code = self.get_text(element)
39
+
40
+ if not name:
41
+ raise ParserError("class requires 'name' attribute")
42
+ if not code or not code.strip():
43
+ raise ParserError("class body cannot be empty")
44
+
45
+ # Parse bases
46
+ bases_attr = self.get_attr(element, 'bases')
47
+ bases = []
48
+ if bases_attr:
49
+ bases = [b.strip() for b in bases_attr.split(',')]
50
+
51
+ # Parse decorators
52
+ decorators_attr = self.get_attr(element, 'decorators')
53
+ decorators = []
54
+ if decorators_attr:
55
+ decorators = [d.strip() for d in decorators_attr.split(',')]
56
+
57
+ return PyClassNode(
58
+ name=name,
59
+ code=code,
60
+ bases=bases,
61
+ decorators=decorators
62
+ )
@@ -0,0 +1,68 @@
1
+ """
2
+ PyDecorator Parser - Parse q:decorator statements
3
+ """
4
+
5
+ import textwrap
6
+ from typing import List
7
+ from xml.etree import ElementTree as ET
8
+ from quantum.core.parsers.base import BaseTagParser
9
+ from quantum.core.ast_nodes import PyDecoratorNode
10
+
11
+
12
+ class PyDecoratorParser(BaseTagParser):
13
+ """
14
+ Parser for q:decorator statements for Python decorator definitions.
15
+
16
+ Examples:
17
+ <!-- Caching decorator -->
18
+ <q:decorator name="cached">
19
+ from functools import wraps
20
+ def decorator(func):
21
+ cache = {}
22
+ @wraps(func)
23
+ def wrapper(*args):
24
+ if args in cache:
25
+ return cache[args]
26
+ result = func(*args)
27
+ cache[args] = result
28
+ return result
29
+ return wrapper
30
+ return decorator
31
+ </q:decorator>
32
+
33
+ <!-- Decorator with parameters -->
34
+ <q:decorator name="retry" params="attempts, delay">
35
+ import time
36
+ def decorator(func):
37
+ def wrapper(*args, **kwargs):
38
+ for i in range(attempts):
39
+ try:
40
+ return func(*args, **kwargs)
41
+ except Exception as e:
42
+ if i == attempts - 1:
43
+ raise
44
+ time.sleep(delay)
45
+ return wrapper
46
+ return decorator
47
+ </q:decorator>
48
+ """
49
+
50
+ @property
51
+ def tag_names(self) -> List[str]:
52
+ return ['decorator', 'pydecorator']
53
+
54
+ def parse(self, element: ET.Element) -> PyDecoratorNode:
55
+ """Parse q:decorator element"""
56
+ name = element.get('name', '')
57
+ code = element.text or ""
58
+ code = textwrap.dedent(code).strip()
59
+
60
+ # Parse params (comma-separated)
61
+ params_str = element.get('params', '')
62
+ params = [p.strip() for p in params_str.split(',') if p.strip()]
63
+
64
+ return PyDecoratorNode(
65
+ name=name,
66
+ code=code,
67
+ params=params
68
+ )
@@ -0,0 +1,52 @@
1
+ """
2
+ PyImport Parser - Parse q:pyimport statements
3
+
4
+ Handles Python module imports.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import PyImportNode
11
+
12
+
13
+ class PyImportParser(BaseTagParser):
14
+ """
15
+ Parser for q:pyimport statements.
16
+
17
+ Supports:
18
+ - Module import with alias
19
+ - Specific name imports
20
+ - Star imports
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['pyimport']
26
+
27
+ def parse(self, element: ET.Element) -> PyImportNode:
28
+ """
29
+ Parse q:pyimport statement.
30
+
31
+ Args:
32
+ element: XML element for q:pyimport
33
+
34
+ Returns:
35
+ PyImportNode AST node
36
+ """
37
+ module = self.get_attr(element, 'module')
38
+
39
+ if not module:
40
+ raise ParserError("pyimport requires 'module' attribute")
41
+
42
+ # Parse names if present
43
+ names_attr = self.get_attr(element, 'names')
44
+ names = []
45
+ if names_attr:
46
+ names = [n.strip() for n in names_attr.split(',')]
47
+
48
+ return PyImportNode(
49
+ module=module,
50
+ alias=self.get_attr(element, 'as'),
51
+ names=names
52
+ )
@@ -0,0 +1,49 @@
1
+ """
2
+ Python Parser - Parse q:python statements
3
+
4
+ Handles embedded Python code.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import PythonNode
11
+
12
+
13
+ class PythonParser(BaseTagParser):
14
+ """
15
+ Parser for q:python statements.
16
+
17
+ Supports:
18
+ - Inline Python code
19
+ - Scope management
20
+ - Async execution
21
+ - Result capture
22
+ """
23
+
24
+ @property
25
+ def tag_names(self) -> List[str]:
26
+ return ['python']
27
+
28
+ def parse(self, element: ET.Element) -> PythonNode:
29
+ """
30
+ Parse q:python statement.
31
+
32
+ Args:
33
+ element: XML element for q:python
34
+
35
+ Returns:
36
+ PythonNode AST node
37
+ """
38
+ code = self.get_text(element)
39
+
40
+ if not code or not code.strip():
41
+ raise ParserError("Python block cannot be empty")
42
+
43
+ return PythonNode(
44
+ code=code,
45
+ scope=self.get_attr(element, 'scope', 'component'),
46
+ async_mode=self.get_bool_attr(element, 'async', False),
47
+ timeout=self.get_attr(element, 'timeout'),
48
+ result=self.get_attr(element, 'result')
49
+ )
@@ -0,0 +1,12 @@
1
+ """
2
+ Services Parsers
3
+
4
+ Parsers for service operations: log, dump, file, mail.
5
+ """
6
+
7
+ from .log_parser import LogParser
8
+ from .dump_parser import DumpParser
9
+ from .file_parser import FileParser
10
+ from .mail_parser import MailParser
11
+
12
+ __all__ = ['LogParser', 'DumpParser', 'FileParser', 'MailParser']
@@ -0,0 +1,52 @@
1
+ """
2
+ Dump Parser - Parse q:dump statements
3
+
4
+ Handles variable inspection and debugging.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser
10
+ from quantum.core.features.dump.src import DumpNode
11
+
12
+
13
+ class DumpParser(BaseTagParser):
14
+ """
15
+ Parser for q:dump statements.
16
+
17
+ Supports:
18
+ - Variable inspection
19
+ - Multiple output formats
20
+ - Depth control
21
+ - Conditional dumping
22
+ """
23
+
24
+ @property
25
+ def tag_names(self) -> List[str]:
26
+ return ['dump']
27
+
28
+ def parse(self, element: ET.Element) -> DumpNode:
29
+ """
30
+ Parse q:dump statement.
31
+
32
+ Args:
33
+ element: XML element for q:dump
34
+
35
+ Returns:
36
+ DumpNode AST node
37
+ """
38
+ var = self.get_attr(element, 'var', '')
39
+ label = self.get_attr(element, 'label', var)
40
+ format_type = self.get_attr(element, 'format', 'text')
41
+ depth = self.get_int_attr(element, 'depth', 3)
42
+ when = self.get_attr(element, 'when')
43
+
44
+ dump_node = DumpNode(
45
+ var=var,
46
+ label=label,
47
+ format=format_type,
48
+ depth=depth,
49
+ when=when
50
+ )
51
+
52
+ return dump_node
@@ -0,0 +1,48 @@
1
+ """
2
+ File Parser - Parse q:file statements
3
+
4
+ Handles file upload and deletion.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import FileNode
11
+
12
+
13
+ class FileParser(BaseTagParser):
14
+ """
15
+ Parser for q:file statements.
16
+
17
+ Supports:
18
+ - File upload with conflict handling
19
+ - File deletion
20
+ - Result storage
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['file']
26
+
27
+ def parse(self, element: ET.Element) -> FileNode:
28
+ """
29
+ Parse q:file statement.
30
+
31
+ Args:
32
+ element: XML element for q:file
33
+
34
+ Returns:
35
+ FileNode AST node
36
+ """
37
+ action = self.get_attr(element, 'action', 'upload')
38
+ file_attr = self.get_attr(element, 'file')
39
+
40
+ if not file_attr:
41
+ raise ParserError("File requires 'file' attribute")
42
+
43
+ file_node = FileNode(action, file_attr)
44
+ file_node.destination = self.get_attr(element, 'destination')
45
+ file_node.name_conflict = self.get_attr(element, 'nameConflict', 'makeUnique')
46
+ file_node.result = self.get_attr(element, 'result')
47
+
48
+ return file_node
@@ -0,0 +1,46 @@
1
+ """
2
+ Log Parser - Parse q:log statements
3
+
4
+ Handles structured logging.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser
10
+ from quantum.core.features.logging.src import LogNode
11
+
12
+
13
+ class LogParser(BaseTagParser):
14
+ """
15
+ Parser for q:log statements.
16
+
17
+ Supports:
18
+ - Log levels (debug, info, warn, error)
19
+ - Conditional logging
20
+ - Context data
21
+ - Correlation IDs
22
+ """
23
+
24
+ @property
25
+ def tag_names(self) -> List[str]:
26
+ return ['log']
27
+
28
+ def parse(self, element: ET.Element) -> LogNode:
29
+ """
30
+ Parse q:log statement.
31
+
32
+ Args:
33
+ element: XML element for q:log
34
+
35
+ Returns:
36
+ LogNode AST node
37
+ """
38
+ level = self.get_attr(element, 'level', 'info')
39
+ message = self.get_attr(element, 'message') or self.get_text(element)
40
+
41
+ log_node = LogNode(level=level, message=message)
42
+ log_node.when = self.get_attr(element, 'when')
43
+ log_node.context = self.get_attr(element, 'context')
44
+ log_node.correlation_id = self.get_attr(element, 'correlationId')
45
+
46
+ return log_node
@@ -0,0 +1,65 @@
1
+ """
2
+ Mail Parser - Parse q:mail statements
3
+
4
+ Handles email sending.
5
+ """
6
+
7
+ from typing import List
8
+ from xml.etree import ElementTree as ET
9
+ from quantum.core.parsers.base import BaseTagParser, ParserError
10
+ from quantum.core.ast_nodes import MailNode
11
+
12
+
13
+ class MailParser(BaseTagParser):
14
+ """
15
+ Parser for q:mail statements.
16
+
17
+ Supports:
18
+ - HTML and plain text emails
19
+ - CC, BCC, Reply-To
20
+ - Attachments
21
+ """
22
+
23
+ @property
24
+ def tag_names(self) -> List[str]:
25
+ return ['mail']
26
+
27
+ def parse(self, element: ET.Element) -> MailNode:
28
+ """
29
+ Parse q:mail statement.
30
+
31
+ Args:
32
+ element: XML element for q:mail
33
+
34
+ Returns:
35
+ MailNode AST node
36
+ """
37
+ to = self.get_attr(element, 'to')
38
+ subject = self.get_attr(element, 'subject')
39
+
40
+ if not to:
41
+ raise ParserError("Mail requires 'to' attribute")
42
+ if not subject:
43
+ raise ParserError("Mail requires 'subject' attribute")
44
+
45
+ mail_node = MailNode(to, subject)
46
+
47
+ # Get body from content or attribute
48
+ mail_node.body = self.get_text(element) or self.get_attr(element, 'body', '')
49
+
50
+ # Optional attributes
51
+ mail_node.from_addr = self.get_attr(element, 'from')
52
+ mail_node.cc = self.get_attr(element, 'cc')
53
+ mail_node.bcc = self.get_attr(element, 'bcc')
54
+ mail_node.reply_to = self.get_attr(element, 'replyTo')
55
+ mail_node.type = self.get_attr(element, 'type', 'html')
56
+
57
+ # Parse attachments
58
+ for child in element:
59
+ child_type = self.get_element_name(child)
60
+ if child_type == 'attachment':
61
+ attachment = self.get_attr(child, 'file')
62
+ if attachment:
63
+ mail_node.attachments.append(attachment)
64
+
65
+ return mail_node
quantum/core/tiers.py ADDED
@@ -0,0 +1,82 @@
1
+ """
2
+ Support tiers for Quantum tags.
3
+
4
+ PRODUCTION_READINESS.md Fase 0. "Production-ready" is meaningful only relative
5
+ to a defined surface, so the surface is defined here, in code, and a tag
6
+ outside the supported set announces itself the first time it is used instead
7
+ of pretending to be first-class.
8
+
9
+ The lists mirror SUPPORT_TIERS.md. When they disagree, this file is the one the
10
+ engine actually enforces, so keep it in step.
11
+ """
12
+
13
+ import logging
14
+
15
+ logger = logging.getLogger("quantum.tiers")
16
+
17
+ # Documented, tested end-to-end, stable. A break here is a critical bug.
18
+ CORE = frozenset({
19
+ "component", "param", "return", "set", "if", "loop", "function",
20
+ "query", "action", "redirect", "flash", "invoke", "data",
21
+ "import", "slot",
22
+ })
23
+
24
+ # The reason the project exists. Same contract as Core is the goal; some of it
25
+ # is still being validated end-to-end (PRODUCTION_READINESS.md Fase 4).
26
+ DIFERENCIAL = frozenset({"llm", "knowledge", "agent", "team"})
27
+
28
+ # Kept and registered, but no stability promise and not in the README. Using
29
+ # one is fine for experiments; relying on one in production is not supported.
30
+ EXPERIMENTAL = frozenset({
31
+ "job", "schedule", "thread",
32
+ "message", "queue", "subscribe", "messageAck", "messageNack",
33
+ "websocket", "websocket-send", "websocket-close",
34
+ "mail", "file", "log", "dump", "persist",
35
+ "python", "pyclass", "pyimport", "class", "decorator", "pydecorator",
36
+ "dispatchEvent", "transaction",
37
+ })
38
+
39
+ SUPPORTED = CORE | DIFERENCIAL
40
+
41
+
42
+ def tier_of(tag_name: str) -> str:
43
+ """'core' | 'diferencial' | 'experimental' | 'unknown'."""
44
+ if tag_name in CORE:
45
+ return "core"
46
+ if tag_name in DIFERENCIAL:
47
+ return "diferencial"
48
+ if tag_name in EXPERIMENTAL:
49
+ return "experimental"
50
+ return "unknown"
51
+
52
+
53
+ # Warn once per tag per process — a q:loop over 1,000 rows must not emit 1,000
54
+ # lines, the same discipline as expression_diagnostics.
55
+ _warned: set = set()
56
+
57
+
58
+ def warn_if_unsupported(tag_name: str) -> None:
59
+ """Emit a one-time warning when an experimental tag is used.
60
+
61
+ Not an error: experimental tags still run. The point is that an operator
62
+ reading the log sees, once, that their app leans on something the project
63
+ does not promise to keep working — the audit found apps built entirely on
64
+ tags that parse and then explode, with nothing warning anyone.
65
+ """
66
+ tier = tier_of(tag_name)
67
+ if tier in ("core", "diferencial", "unknown"):
68
+ # 'unknown' is handled by the parser's own error path, not here.
69
+ return
70
+ if tag_name in _warned:
71
+ return
72
+ _warned.add(tag_name)
73
+ logger.warning(
74
+ "q:%s is EXPERIMENTAL — not covered by the production support surface "
75
+ "(SUPPORT_TIERS.md). It may change or break without notice; do not rely "
76
+ "on it in production.", tag_name
77
+ )
78
+
79
+
80
+ def reset_warnings() -> None:
81
+ """For tests, and for a reloading server."""
82
+ _warned.clear()