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,81 @@
1
+ """XML into an ElementTree whose elements know their line (M2, DEV-2).
2
+
3
+ `xml.etree` does not keep source positions, so an error found after parsing —
4
+ a statement inside markup, an unknown attribute, a failing expression — could
5
+ name the tag but not where it is. This builds the same tree with expat (the
6
+ parser ElementTree itself runs on) and sets `element.sourceline` on each
7
+ element.
8
+ """
9
+
10
+ from xml.etree import ElementTree as ET
11
+ from xml.parsers import expat
12
+
13
+
14
+ class _Element(ET.Element):
15
+ """An Element that can carry `sourceline` (the C Element takes no new attributes)."""
16
+ sourceline = None
17
+
18
+
19
+ def fromstring_with_lines(text: str) -> ET.Element:
20
+ """Like ET.fromstring(text); every element gets `sourceline` (1-based)."""
21
+ builder = ET.TreeBuilder(element_factory=_Element)
22
+ parser = expat.ParserCreate(None, '}')
23
+ parser.buffer_text = True
24
+ parser.ordered_attributes = True
25
+
26
+ def nome(bruto: str) -> str:
27
+ # expat with a separator reports "uri}local"; ElementTree spells it "{uri}local".
28
+ return '{' + bruto if '}' in bruto else bruto
29
+
30
+ def inicio(tag, atributos):
31
+ pares = dict(zip(atributos[0::2], atributos[1::2]))
32
+ elemento = builder.start(nome(tag), {nome(k): v for k, v in pares.items()})
33
+ elemento.sourceline = parser.CurrentLineNumber
34
+
35
+ parser.StartElementHandler = inicio
36
+ parser.EndElementHandler = lambda tag: builder.end(nome(tag))
37
+ parser.CharacterDataHandler = builder.data
38
+ try:
39
+ parser.Parse(text, True)
40
+ except expat.ExpatError as exc:
41
+ erro = ET.ParseError(str(exc))
42
+ erro.code = exc.code
43
+ erro.position = (exc.lineno, exc.offset)
44
+ raise erro from None
45
+ return builder.close()
46
+
47
+
48
+ def line_of(item) -> int:
49
+ """The source line of an element or an AST node, or None."""
50
+ return getattr(item, 'sourceline', None) or getattr(item, 'source_line', None)
51
+
52
+
53
+ def tag_error(exc: BaseException, node) -> None:
54
+ """DEV-2: the innermost node an error passes through names its file and line.
55
+
56
+ Innermost across wrapping too: an error in a called component is re-raised
57
+ as a new exception by the page; the line inside the component, already in
58
+ the chain, wins over the line of the call."""
59
+ if error_location(exc)[1] is not None:
60
+ return
61
+ linha = getattr(node, 'source_line', None)
62
+ if not linha:
63
+ return
64
+ try:
65
+ exc.quantum_line = linha
66
+ exc.quantum_file = getattr(node, 'source_file', None)
67
+ except (AttributeError, TypeError):
68
+ pass # an exception type with __slots__
69
+
70
+
71
+ def error_location(exc: BaseException):
72
+ """(file, line) of an error or of any error it wraps; (None, None) if unknown."""
73
+ visto = set()
74
+ while exc is not None and id(exc) not in visto:
75
+ visto.add(id(exc))
76
+ if getattr(exc, 'quantum_line', None) is not None:
77
+ return getattr(exc, 'quantum_file', None), exc.quantum_line
78
+ if getattr(exc, 'line', None) is not None and type(exc).__name__ == 'QuantumParseError':
79
+ return getattr(exc, 'file', None), exc.line
80
+ exc = exc.__cause__ or exc.__context__
81
+ return None, None
@@ -0,0 +1,28 @@
1
+ """
2
+ Quantum Package Manager
3
+
4
+ Package management system for sharing Quantum components.
5
+
6
+ Features:
7
+ - Package manifest handling (quantum.yaml)
8
+ - Local package registry (~/.quantum/packages/)
9
+ - Dependency resolution with version constraints
10
+ - Install, remove, list, search operations
11
+ - CLI integration (quantum pkg ...)
12
+ """
13
+
14
+ from .manifest import PackageManifest, ManifestError
15
+ from .registry import PackageRegistry, RegistryError
16
+ from .resolver import DependencyResolver, ResolutionError
17
+ from .manager import PackageManager, PackageError
18
+
19
+ __all__ = [
20
+ 'PackageManifest',
21
+ 'ManifestError',
22
+ 'PackageRegistry',
23
+ 'RegistryError',
24
+ 'DependencyResolver',
25
+ 'ResolutionError',
26
+ 'PackageManager',
27
+ 'PackageError',
28
+ ]
@@ -0,0 +1,413 @@
1
+ """
2
+ Quantum Package Manager
3
+
4
+ Main package manager that coordinates manifest, registry, and resolver.
5
+
6
+ Usage:
7
+ from quantum.packages import PackageManager
8
+
9
+ pm = PackageManager()
10
+ pm.init('/path/to/new-package')
11
+ pm.install('/path/to/package-source')
12
+ pm.install_from_git('https://github.com/user/quantum-component.git')
13
+ pm.remove('my-component')
14
+ pm.list_packages()
15
+ pm.search('button')
16
+ """
17
+
18
+ import os
19
+ import shutil
20
+ import tempfile
21
+ import tarfile
22
+ import subprocess
23
+ from pathlib import Path
24
+ from typing import Dict, List, Optional, Any
25
+
26
+ from .manifest import PackageManifest, ManifestError, init_package
27
+ from .registry import PackageRegistry, RegistryError
28
+ from .resolver import DependencyResolver, ResolutionError, ResolvedPackage
29
+
30
+
31
+ class PackageError(Exception):
32
+ """General package manager error."""
33
+ pass
34
+
35
+
36
+ class PackageManager:
37
+ """
38
+ Main package manager for Quantum components.
39
+
40
+ Handles:
41
+ - Package initialization (quantum pkg init)
42
+ - Package publishing (quantum pkg publish)
43
+ - Package installation (quantum pkg install)
44
+ - Package removal (quantum pkg remove)
45
+ - Package listing (quantum pkg list)
46
+ - Package search (quantum pkg search)
47
+ """
48
+
49
+ def __init__(self, registry_path: Optional[Path] = None):
50
+ """
51
+ Initialize package manager.
52
+
53
+ Args:
54
+ registry_path: Custom registry path (default: ~/.quantum)
55
+ """
56
+ self.registry = PackageRegistry(registry_path)
57
+ self.resolver = DependencyResolver(self.registry)
58
+
59
+ def init(
60
+ self,
61
+ path: str,
62
+ name: Optional[str] = None,
63
+ description: str = "",
64
+ author: str = "",
65
+ license_id: str = "MIT"
66
+ ) -> PackageManifest:
67
+ """
68
+ Initialize a new package in the given directory.
69
+
70
+ Creates package structure with quantum.yaml, src/, examples/, README.md.
71
+
72
+ Args:
73
+ path: Directory to initialize package in
74
+ name: Package name (default: directory name)
75
+ description: Package description
76
+ author: Package author
77
+ license_id: License identifier
78
+
79
+ Returns:
80
+ Created package manifest
81
+ """
82
+ path = Path(path)
83
+
84
+ # Check if already initialized
85
+ manifest_path = path / 'quantum.yaml'
86
+ if manifest_path.exists():
87
+ raise PackageError(f"Package already initialized at {path}")
88
+
89
+ try:
90
+ manifest = init_package(
91
+ path=path,
92
+ name=name,
93
+ description=description,
94
+ author=author,
95
+ license_id=license_id
96
+ )
97
+ return manifest
98
+ except ManifestError as e:
99
+ raise PackageError(f"Failed to initialize package: {e}")
100
+
101
+ def install(
102
+ self,
103
+ source: str,
104
+ version: Optional[str] = None,
105
+ resolve_deps: bool = True
106
+ ) -> List[PackageManifest]:
107
+ """
108
+ Install a package from local path or URL.
109
+
110
+ Args:
111
+ source: Package source (local path, git URL, or package name)
112
+ version: Specific version to install (for registered packages)
113
+ resolve_deps: Whether to resolve and install dependencies
114
+
115
+ Returns:
116
+ List of installed package manifests
117
+ """
118
+ installed = []
119
+ source_path = None
120
+ temp_dir = None
121
+
122
+ try:
123
+ # Determine source type
124
+ if source.startswith('http://') or source.startswith('https://'):
125
+ if '.git' in source or 'github.com' in source:
126
+ # Git URL
127
+ temp_dir = Path(tempfile.mkdtemp())
128
+ source_path = self._clone_git(source, temp_dir)
129
+ else:
130
+ raise PackageError(f"Unsupported URL: {source}")
131
+ elif os.path.exists(source):
132
+ # Local path
133
+ source_path = Path(source)
134
+ else:
135
+ # Check if it's already installed (for dependency resolution)
136
+ if self.registry.has_package(source, version):
137
+ manifest = self.registry.get_package(source, version)
138
+ if manifest:
139
+ return [manifest]
140
+
141
+ raise PackageError(
142
+ f"Package not found: {source}. "
143
+ "Provide a local path or git URL."
144
+ )
145
+
146
+ # Load and validate manifest
147
+ manifest_path = source_path / 'quantum.yaml'
148
+ if not manifest_path.exists():
149
+ raise PackageError(f"No quantum.yaml found in {source_path}")
150
+
151
+ try:
152
+ manifest = PackageManifest.load(manifest_path)
153
+ except ManifestError as e:
154
+ raise PackageError(f"Invalid manifest: {e}")
155
+
156
+ # Resolve and install dependencies first
157
+ if resolve_deps and manifest.dependencies:
158
+ for dep_name, dep_version in manifest.dependencies.items():
159
+ if not self.registry.has_package(dep_name):
160
+ raise PackageError(
161
+ f"Missing dependency: {dep_name}. "
162
+ f"Install it first: quantum pkg install <path-to-{dep_name}>"
163
+ )
164
+
165
+ # Check version constraint
166
+ try:
167
+ resolved = self.resolver.resolve(dep_name, dep_version)
168
+ installed.append(resolved.manifest)
169
+ except ResolutionError as e:
170
+ raise PackageError(f"Dependency resolution failed: {e}")
171
+
172
+ # Install the main package
173
+ try:
174
+ installed_manifest = self.registry.install_package(source_path, manifest)
175
+ installed.append(installed_manifest)
176
+ except RegistryError as e:
177
+ raise PackageError(f"Installation failed: {e}")
178
+
179
+ return installed
180
+
181
+ finally:
182
+ # Clean up temp directory
183
+ if temp_dir and temp_dir.exists():
184
+ shutil.rmtree(temp_dir, ignore_errors=True)
185
+
186
+ def install_from_git(self, git_url: str, ref: Optional[str] = None) -> List[PackageManifest]:
187
+ """
188
+ Install a package from a git repository.
189
+
190
+ Args:
191
+ git_url: Git repository URL
192
+ ref: Git ref (branch, tag, commit) to checkout
193
+
194
+ Returns:
195
+ List of installed package manifests
196
+ """
197
+ temp_dir = Path(tempfile.mkdtemp())
198
+ try:
199
+ source_path = self._clone_git(git_url, temp_dir, ref)
200
+ return self.install(str(source_path))
201
+ finally:
202
+ shutil.rmtree(temp_dir, ignore_errors=True)
203
+
204
+ def remove(
205
+ self,
206
+ package_name: str,
207
+ version: Optional[str] = None
208
+ ) -> bool:
209
+ """
210
+ Remove an installed package.
211
+
212
+ Args:
213
+ package_name: Name of package to remove
214
+ version: Specific version to remove (None = all versions)
215
+
216
+ Returns:
217
+ True if removed, False if not found
218
+ """
219
+ if not self.registry.has_package(package_name, version):
220
+ return False
221
+
222
+ try:
223
+ return self.registry.remove_package(package_name, version)
224
+ except RegistryError as e:
225
+ raise PackageError(f"Failed to remove package: {e}")
226
+
227
+ def list_packages(self) -> List[Dict[str, Any]]:
228
+ """
229
+ List all installed packages.
230
+
231
+ Returns:
232
+ List of package info dictionaries
233
+ """
234
+ return self.registry.list_packages()
235
+
236
+ def search(self, query: str) -> List[Dict[str, Any]]:
237
+ """
238
+ Search installed packages.
239
+
240
+ Args:
241
+ query: Search query (matches name, keywords, description)
242
+
243
+ Returns:
244
+ List of matching package info dictionaries
245
+ """
246
+ return self.registry.search_packages(query)
247
+
248
+ def get_package(
249
+ self,
250
+ package_name: str,
251
+ version: Optional[str] = None
252
+ ) -> Optional[PackageManifest]:
253
+ """
254
+ Get an installed package manifest.
255
+
256
+ Args:
257
+ package_name: Package name
258
+ version: Specific version (None = latest)
259
+
260
+ Returns:
261
+ Package manifest or None
262
+ """
263
+ return self.registry.get_package(package_name, version)
264
+
265
+ def get_package_path(
266
+ self,
267
+ package_name: str,
268
+ version: Optional[str] = None
269
+ ) -> Optional[Path]:
270
+ """
271
+ Get path to an installed package.
272
+
273
+ Args:
274
+ package_name: Package name
275
+ version: Specific version (None = latest)
276
+
277
+ Returns:
278
+ Path to package directory or None
279
+ """
280
+ return self.registry.get_package_path(package_name, version)
281
+
282
+ def publish(self, source_path: str) -> Path:
283
+ """
284
+ Create a publishable package archive.
285
+
286
+ Creates a .tar.gz archive that can be shared or uploaded to a registry.
287
+
288
+ Args:
289
+ source_path: Path to package directory
290
+
291
+ Returns:
292
+ Path to created archive
293
+ """
294
+ source_path = Path(source_path)
295
+
296
+ # Load and validate manifest
297
+ manifest_path = source_path / 'quantum.yaml'
298
+ if not manifest_path.exists():
299
+ raise PackageError(f"No quantum.yaml found in {source_path}")
300
+
301
+ try:
302
+ manifest = PackageManifest.load(manifest_path)
303
+ except ManifestError as e:
304
+ raise PackageError(f"Invalid manifest: {e}")
305
+
306
+ # Create archive
307
+ archive_name = f"{manifest.name}-{manifest.version}.tar.gz"
308
+ archive_path = source_path.parent / archive_name
309
+
310
+ with tarfile.open(archive_path, 'w:gz') as tar:
311
+ for item in source_path.iterdir():
312
+ if item.name.startswith('.'):
313
+ continue # Skip hidden files
314
+ if item.name.endswith('.tar.gz'):
315
+ continue # Skip existing archives
316
+ tar.add(item, arcname=item.name)
317
+
318
+ return archive_path
319
+
320
+ def resolve_dependencies(
321
+ self,
322
+ package_name: str,
323
+ version_constraint: str = '*'
324
+ ) -> ResolvedPackage:
325
+ """
326
+ Resolve package dependencies.
327
+
328
+ Args:
329
+ package_name: Package to resolve
330
+ version_constraint: Version constraint
331
+
332
+ Returns:
333
+ Resolved package with dependencies
334
+ """
335
+ try:
336
+ return self.resolver.resolve(package_name, version_constraint)
337
+ except ResolutionError as e:
338
+ raise PackageError(f"Dependency resolution failed: {e}")
339
+
340
+ def get_component_path(
341
+ self,
342
+ package_name: str,
343
+ component_name: Optional[str] = None
344
+ ) -> Optional[Path]:
345
+ """
346
+ Get path to a component file in a package.
347
+
348
+ Args:
349
+ package_name: Package name
350
+ component_name: Component name (None = main component)
351
+
352
+ Returns:
353
+ Path to component file or None
354
+ """
355
+ manifest = self.get_package(package_name)
356
+ if not manifest:
357
+ return None
358
+
359
+ if component_name is None:
360
+ # Return main component
361
+ return manifest.get_main_component_path()
362
+
363
+ # Search for component in package
364
+ pkg_path = self.get_package_path(package_name)
365
+ if not pkg_path:
366
+ return None
367
+
368
+ # Try src/{ComponentName}.q
369
+ component_path = pkg_path / 'src' / f'{component_name}.q'
370
+ if component_path.exists():
371
+ return component_path
372
+
373
+ # Try src/{component_name}.q (lowercase)
374
+ component_path = pkg_path / 'src' / f'{component_name.lower()}.q'
375
+ if component_path.exists():
376
+ return component_path
377
+
378
+ return None
379
+
380
+ def _clone_git(
381
+ self,
382
+ git_url: str,
383
+ dest_dir: Path,
384
+ ref: Optional[str] = None
385
+ ) -> Path:
386
+ """Clone a git repository."""
387
+ try:
388
+ cmd = ['git', 'clone', '--depth', '1']
389
+ if ref:
390
+ cmd.extend(['--branch', ref])
391
+ cmd.extend([git_url, str(dest_dir / 'repo')])
392
+
393
+ result = subprocess.run(
394
+ cmd,
395
+ capture_output=True,
396
+ text=True,
397
+ timeout=60
398
+ )
399
+
400
+ if result.returncode != 0:
401
+ raise PackageError(f"Git clone failed: {result.stderr}")
402
+
403
+ return dest_dir / 'repo'
404
+
405
+ except subprocess.TimeoutExpired:
406
+ raise PackageError("Git clone timed out")
407
+ except FileNotFoundError:
408
+ raise PackageError("Git not found. Please install git.")
409
+
410
+
411
+ def get_package_manager() -> PackageManager:
412
+ """Get default package manager instance."""
413
+ return PackageManager()