chemunited 0.0.1__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 (371) hide show
  1. chemunited/__init__.py +3 -0
  2. chemunited/__main__.py +53 -0
  3. chemunited/connectivity/__init__.py +0 -0
  4. chemunited/connectivity/graph.py +77 -0
  5. chemunited/connectivity/online_list.py +364 -0
  6. chemunited/connectivity/openapi_commands.py +248 -0
  7. chemunited/draw/__init__.py +0 -0
  8. chemunited/draw/graph.py +376 -0
  9. chemunited/draw/tree_add.py +287 -0
  10. chemunited/elements/__init__.py +3 -0
  11. chemunited/elements/access.py +176 -0
  12. chemunited/elements/component/__init__.py +13 -0
  13. chemunited/elements/component/__test_component.py +64 -0
  14. chemunited/elements/component/component_factory.py +159 -0
  15. chemunited/elements/component/component_parts/__init__.py +24 -0
  16. chemunited/elements/component/component_parts/connection_point.py +157 -0
  17. chemunited/elements/component/component_parts/flow_channel.py +0 -0
  18. chemunited/elements/component/component_parts/scene_item.py +379 -0
  19. chemunited/elements/component/component_parts/svg_layer.py +90 -0
  20. chemunited/elements/component/component_parts/text_element.py +22 -0
  21. chemunited/elements/component/connectivity.py +56 -0
  22. chemunited/elements/component/glossary/__init__.py +61 -0
  23. chemunited/elements/component/glossary/analytics/__init__.py +0 -0
  24. chemunited/elements/component/glossary/analytics/hplccontrol_graph.py +28 -0
  25. chemunited/elements/component/glossary/analytics/ircontrol_graph.py +26 -0
  26. chemunited/elements/component/glossary/analytics/mscontrol_graph.py +28 -0
  27. chemunited/elements/component/glossary/analytics/nmrcontrol_graph.py +28 -0
  28. chemunited/elements/component/glossary/analytics/spectrum.py +50 -0
  29. chemunited/elements/component/glossary/assembly/__init__.py +0 -0
  30. chemunited/elements/component/glossary/pipes/__init__.py +0 -0
  31. chemunited/elements/component/glossary/pipes/distributor_graph.py +44 -0
  32. chemunited/elements/component/glossary/pipes/mfc_graph.py +21 -0
  33. chemunited/elements/component/glossary/pumps/__init__.py +0 -0
  34. chemunited/elements/component/glossary/pumps/syringepump_graph.py +92 -0
  35. chemunited/elements/component/glossary/sensors/__init__.py +0 -0
  36. chemunited/elements/component/glossary/technical/__init__.py +0 -0
  37. chemunited/elements/component/glossary/technical/multichannel_graph.py +56 -0
  38. chemunited/elements/component/glossary/thermal/__init__.py +0 -0
  39. chemunited/elements/component/glossary/valve/__init__.py +0 -0
  40. chemunited/elements/component/glossary/valve/rotary_valve_graph.py +92 -0
  41. chemunited/elements/component/glossary/valve/solenoid_valve_graph.py +164 -0
  42. chemunited/elements/component/glossary/vessels/__init__.py +0 -0
  43. chemunited/elements/component/glossary/vessels/common.py +45 -0
  44. chemunited/elements/component/glossary/vessels/customflask_graph.py +93 -0
  45. chemunited/elements/component/glossary/vessels/flowreactor_graph.py +99 -0
  46. chemunited/elements/component/glossary/vessels/glassbottle_graph.py +92 -0
  47. chemunited/elements/component/glossary/vessels/loop_graph.py +75 -0
  48. chemunited/elements/component/glossary/vessels/vial_graph.py +211 -0
  49. chemunited/elements/component/graph_item.py +625 -0
  50. chemunited/elements/component/protocols/__init__.py +30 -0
  51. chemunited/elements/component/widgets/__init__.py +5 -0
  52. chemunited/elements/component/widgets/connectivity.py +35 -0
  53. chemunited/elements/component/widgets/main.py +67 -0
  54. chemunited/elements/component/widgets/properties.py +34 -0
  55. chemunited/elements/compounds/__init__.py +5 -0
  56. chemunited/elements/compounds/compound_dialog.py +117 -0
  57. chemunited/elements/compounds/compound_list.py +285 -0
  58. chemunited/elements/compounds/compounds_widget.py +44 -0
  59. chemunited/elements/compounds/coolprop_lookup.py +179 -0
  60. chemunited/elements/connection/__connection_test.py +128 -0
  61. chemunited/elements/connection/__init__.py +17 -0
  62. chemunited/elements/connection/connection.py +404 -0
  63. chemunited/elements/inventory/__init__.py +5 -0
  64. chemunited/elements/inventory/workspace.py +1251 -0
  65. chemunited/elements/pool_commands.py +71 -0
  66. chemunited/elements/reactions/__init__.py +11 -0
  67. chemunited/elements/reactions/model.py +33 -0
  68. chemunited/elements/reactions/reaction_dialog.py +108 -0
  69. chemunited/elements/reactions/reaction_list.py +132 -0
  70. chemunited/elements/reactions/reactions_widget.py +28 -0
  71. chemunited/mcp/MCP_CLIENT_CONFIG.md +99 -0
  72. chemunited/mcp/__init__.py +6 -0
  73. chemunited/mcp/instructions.md +287 -0
  74. chemunited/mcp/project_files.py +122 -0
  75. chemunited/mcp/qt_bridge.py +46 -0
  76. chemunited/mcp/server.py +226 -0
  77. chemunited/monitor.py +237 -0
  78. chemunited/monitoring/__init__.py +0 -0
  79. chemunited/monitoring/execution_api_process.py +387 -0
  80. chemunited/monitoring/graph.py +14 -0
  81. chemunited/monitoring/pool_log_tailer.py +106 -0
  82. chemunited/monitoring/process_list.py +100 -0
  83. chemunited/monitoring/status_animated.py +90 -0
  84. chemunited/monitoring/summary.py +728 -0
  85. chemunited/orchestrator/__init__.py +5 -0
  86. chemunited/orchestrator/connectivity.py +154 -0
  87. chemunited/orchestrator/core.py +118 -0
  88. chemunited/orchestrator/draw.py +468 -0
  89. chemunited/orchestrator/execution.py +1020 -0
  90. chemunited/orchestrator/inventory_state.py +158 -0
  91. chemunited/orchestrator/main.py +5 -0
  92. chemunited/orchestrator/orchestrator.py +5 -0
  93. chemunited/orchestrator/project_file.py +1283 -0
  94. chemunited/orchestrator/protocols.py +163 -0
  95. chemunited/pre_run/__init__.py +0 -0
  96. chemunited/pre_run/dashboard_launcher.py +695 -0
  97. chemunited/pre_run/pre_run_frame.py +69 -0
  98. chemunited/pre_run/process_list.py +448 -0
  99. chemunited/pre_run/protocols_historic.py +231 -0
  100. chemunited/pre_run/summary_window.py +235 -0
  101. chemunited/project/__init__.py +0 -0
  102. chemunited/project/git_manager.py +225 -0
  103. chemunited/project/manifest.py +35 -0
  104. chemunited/project/platform_svg.py +139 -0
  105. chemunited/project/recent.py +104 -0
  106. chemunited/project/session.py +217 -0
  107. chemunited/project/storage.py +958 -0
  108. chemunited/project/writer.py +92 -0
  109. chemunited/protocols/__init__.py +0 -0
  110. chemunited/protocols/graph.py +6 -0
  111. chemunited/protocols/process_list.py +94 -0
  112. chemunited/protocols/workflows/__init__.py +12 -0
  113. chemunited/protocols/workflows/controller.py +192 -0
  114. chemunited/protocols/workflows/design.py +39 -0
  115. chemunited/protocols/workflows/editor.py +529 -0
  116. chemunited/protocols/workflows/elements/__init__.py +7 -0
  117. chemunited/protocols/workflows/elements/access_point.py +168 -0
  118. chemunited/protocols/workflows/elements/status_bar.py +136 -0
  119. chemunited/protocols/workflows/elements/style.py +44 -0
  120. chemunited/protocols/workflows/elements/work_connection.py +606 -0
  121. chemunited/protocols/workflows/elements/work_node.py +443 -0
  122. chemunited/protocols/workflows/exceptions.py +6 -0
  123. chemunited/protocols/workflows/naming.py +12 -0
  124. chemunited/protocols/workflows/node_parameters_dialog.py +236 -0
  125. chemunited/protocols/workflows/process_workflow.py +406 -0
  126. chemunited/protocols/workflows/workflow_frames.py +1598 -0
  127. chemunited/protocols/workflows/workflow_rules.py +140 -0
  128. chemunited/protocols/workflows/workflow_widget.py +169 -0
  129. chemunited/setup.py +529 -0
  130. chemunited/shared/editor/__init__.py +0 -0
  131. chemunited/shared/editor/base.py +181 -0
  132. chemunited/shared/editor/editor.py +0 -0
  133. chemunited/shared/editor/lexer.py +108 -0
  134. chemunited/shared/editor/parameters/cards.py +703 -0
  135. chemunited/shared/editor/parameters/drag_list.py +155 -0
  136. chemunited/shared/editor/parameters/example.py +121 -0
  137. chemunited/shared/editor/parameters/list.py +117 -0
  138. chemunited/shared/editor/parameters/main.py +528 -0
  139. chemunited/shared/editor/protocols/command.py +296 -0
  140. chemunited/shared/editor/protocols/command_list.py +462 -0
  141. chemunited/shared/editor/protocols/example.py +246 -0
  142. chemunited/shared/editor/protocols/node_metadata.py +36 -0
  143. chemunited/shared/editor/protocols/param_ref_card.py +165 -0
  144. chemunited/shared/editor/protocols/script.py +419 -0
  145. chemunited/shared/enums/__init__.py +10 -0
  146. chemunited/shared/enums/elements_scene.py +8 -0
  147. chemunited/shared/enums/protocols_enum.py +10 -0
  148. chemunited/shared/enums/windows_enum.py +17 -0
  149. chemunited/shared/graph/__init__.py +7 -0
  150. chemunited/shared/graph/graph_core.py +190 -0
  151. chemunited/shared/graph/scene_core.py +37 -0
  152. chemunited/shared/graph_objects/__init__.py +6 -0
  153. chemunited/shared/graph_objects/custom_path.py +184 -0
  154. chemunited/shared/icon.py +78 -0
  155. chemunited/shared/logger_queue.py +132 -0
  156. chemunited/shared/prcess_list/__init__.py +5 -0
  157. chemunited/shared/prcess_list/item.py +261 -0
  158. chemunited/shared/prcess_list/list.py +154 -0
  159. chemunited/shared/prcess_list/widget.py +107 -0
  160. chemunited/shared/resources/README.md +177 -0
  161. chemunited/shared/resources/__init__.py +0 -0
  162. chemunited/shared/resources/components/ADC.svg +32 -0
  163. chemunited/shared/resources/components/BackPressureRegulator.svg +48 -0
  164. chemunited/shared/resources/components/BottleAccess.svg +34 -0
  165. chemunited/shared/resources/components/BottlePressureAccess.svg +34 -0
  166. chemunited/shared/resources/components/BubbleSensor.svg +46 -0
  167. chemunited/shared/resources/components/Chiller.svg +106 -0
  168. chemunited/shared/resources/components/CustomFlask.svg +54 -0
  169. chemunited/shared/resources/components/DAC.svg +32 -0
  170. chemunited/shared/resources/components/Distributor.svg +20 -0
  171. chemunited/shared/resources/components/FlaskJacket.svg +20 -0
  172. chemunited/shared/resources/components/FlowMeter.svg +49 -0
  173. chemunited/shared/resources/components/FlowReactor.svg +131 -0
  174. chemunited/shared/resources/components/FlowReactorBase.svg +20 -0
  175. chemunited/shared/resources/components/FourPortDistributionValve.svg +308 -0
  176. chemunited/shared/resources/components/FourPortFivePositionValve.svg +282 -0
  177. chemunited/shared/resources/components/Gantry3D.svg +199 -0
  178. chemunited/shared/resources/components/GlassBottle.svg +75 -0
  179. chemunited/shared/resources/components/HPLC.svg +116 -0
  180. chemunited/shared/resources/components/HPLCControl.svg +1023 -0
  181. chemunited/shared/resources/components/HPLCPump.svg +79 -0
  182. chemunited/shared/resources/components/IRControl.svg +36 -0
  183. chemunited/shared/resources/components/LengthControl.svg +66 -0
  184. chemunited/shared/resources/components/Loop.svg +128 -0
  185. chemunited/shared/resources/components/LoopBase.svg +23 -0
  186. chemunited/shared/resources/components/MFCComponent.svg +226 -0
  187. chemunited/shared/resources/components/MSControl.svg +79 -0
  188. chemunited/shared/resources/components/MassFlowControl.svg +40 -0
  189. chemunited/shared/resources/components/MultiChannelADC.svg +238 -0
  190. chemunited/shared/resources/components/MultiChannelDAC.svg +238 -0
  191. chemunited/shared/resources/components/MultiChannelRelay.svg +220 -0
  192. chemunited/shared/resources/components/NMRControl.svg +48 -0
  193. chemunited/shared/resources/components/Peltier.svg +76 -0
  194. chemunited/shared/resources/components/PeltierCoolerTemperatureControl.svg +553 -0
  195. chemunited/shared/resources/components/PhidgetBubbleSensorComponent.svg +256 -0
  196. chemunited/shared/resources/components/PhidgetBubbleSensorPowerComponent.svg +59 -0
  197. chemunited/shared/resources/components/PhotoLeds.svg +57 -0
  198. chemunited/shared/resources/components/PhotoSensor.svg +144 -0
  199. chemunited/shared/resources/components/Photoreactor.svg +296 -0
  200. chemunited/shared/resources/components/PoolDARK.svg +91 -0
  201. chemunited/shared/resources/components/PoolLIGHT.svg +91 -0
  202. chemunited/shared/resources/components/Power.svg +27 -0
  203. chemunited/shared/resources/components/PowerControl.svg +59 -0
  204. chemunited/shared/resources/components/PowerSwitch.svg +59 -0
  205. chemunited/shared/resources/components/PressureControl.svg +294 -0
  206. chemunited/shared/resources/components/PressureSensor.svg +287 -0
  207. chemunited/shared/resources/components/Relay.svg +26 -0
  208. chemunited/shared/resources/components/RotaryValve.svg +37 -0
  209. chemunited/shared/resources/components/Separator.svg +53 -0
  210. chemunited/shared/resources/components/Sink.svg +77 -0
  211. chemunited/shared/resources/components/SixPortDistributionValve.svg +364 -0
  212. chemunited/shared/resources/components/SixPortTwoPositionValve.svg +352 -0
  213. chemunited/shared/resources/components/SixteenPortDistributionValve.svg +644 -0
  214. chemunited/shared/resources/components/SolenoidValve.svg +33 -0
  215. chemunited/shared/resources/components/SolenoidValve2Way.svg +39 -0
  216. chemunited/shared/resources/components/Source.svg +77 -0
  217. chemunited/shared/resources/components/SourceSink.svg +22 -0
  218. chemunited/shared/resources/components/SyringeBarrel.svg +101 -0
  219. chemunited/shared/resources/components/SyringePlunger.svg +24 -0
  220. chemunited/shared/resources/components/SyringePump.svg +704 -0
  221. chemunited/shared/resources/components/TemperatureControl.svg +1089 -0
  222. chemunited/shared/resources/components/ThreePortFourPositionValve.svg +283 -0
  223. chemunited/shared/resources/components/ThreePortTwoPositionValve.svg +264 -0
  224. chemunited/shared/resources/components/TwelvePortDistributionValve.svg +532 -0
  225. chemunited/shared/resources/components/TwoPortDistributionValve.svg +252 -0
  226. chemunited/shared/resources/components/Vial.svg +301 -0
  227. chemunited/shared/resources/icons/add_folder_black.svg +14 -0
  228. chemunited/shared/resources/icons/add_folder_white.svg +14 -0
  229. chemunited/shared/resources/icons/air.svg +4 -0
  230. chemunited/shared/resources/icons/block_for_black.svg +4 -0
  231. chemunited/shared/resources/icons/block_for_white.svg +4 -0
  232. chemunited/shared/resources/icons/block_if_black.svg +7 -0
  233. chemunited/shared/resources/icons/block_if_white.svg +11 -0
  234. chemunited/shared/resources/icons/boolean_black.svg +13 -0
  235. chemunited/shared/resources/icons/boolean_white.svg +13 -0
  236. chemunited/shared/resources/icons/build.svg +12 -0
  237. chemunited/shared/resources/icons/chemical_black.svg +11 -0
  238. chemunited/shared/resources/icons/chemical_white.svg +7 -0
  239. chemunited/shared/resources/icons/chemunited.ico +0 -0
  240. chemunited/shared/resources/icons/chemunited.svg +346 -0
  241. chemunited/shared/resources/icons/chemunited_simu.svg +689 -0
  242. chemunited/shared/resources/icons/choices_black.svg +11 -0
  243. chemunited/shared/resources/icons/choices_white.svg +11 -0
  244. chemunited/shared/resources/icons/color_select_black.svg +6 -0
  245. chemunited/shared/resources/icons/color_select_white.svg +6 -0
  246. chemunited/shared/resources/icons/complete.svg +1 -0
  247. chemunited/shared/resources/icons/component_icon.svg +1 -0
  248. chemunited/shared/resources/icons/connection_black.svg +13 -0
  249. chemunited/shared/resources/icons/connection_white.svg +15 -0
  250. chemunited/shared/resources/icons/csv.svg +10 -0
  251. chemunited/shared/resources/icons/database_black.svg +1 -0
  252. chemunited/shared/resources/icons/database_white.svg +1 -0
  253. chemunited/shared/resources/icons/device_hierarchy.svg +1 -0
  254. chemunited/shared/resources/icons/flowchem_logo.svg +33 -0
  255. chemunited/shared/resources/icons/home.svg +13 -0
  256. chemunited/shared/resources/icons/inspect_black.svg +9 -0
  257. chemunited/shared/resources/icons/inspect_white.svg +9 -0
  258. chemunited/shared/resources/icons/integer_black.svg +15 -0
  259. chemunited/shared/resources/icons/integer_white.svg +15 -0
  260. chemunited/shared/resources/icons/json.svg +7 -0
  261. chemunited/shared/resources/icons/line_pressure_black.svg +23 -0
  262. chemunited/shared/resources/icons/line_pressure_white.svg +23 -0
  263. chemunited/shared/resources/icons/link_black.svg +4 -0
  264. chemunited/shared/resources/icons/link_white.svg +4 -0
  265. chemunited/shared/resources/icons/list_black.svg +1 -0
  266. chemunited/shared/resources/icons/list_white.svg +6 -0
  267. chemunited/shared/resources/icons/log.svg +12 -0
  268. chemunited/shared/resources/icons/logo.svg +389 -0
  269. chemunited/shared/resources/icons/manual_black.svg +12 -0
  270. chemunited/shared/resources/icons/manual_white.svg +12 -0
  271. chemunited/shared/resources/icons/measure_black.svg +38 -0
  272. chemunited/shared/resources/icons/measure_white.svg +38 -0
  273. chemunited/shared/resources/icons/module.svg +1 -0
  274. chemunited/shared/resources/icons/molecule_black.svg +48 -0
  275. chemunited/shared/resources/icons/molecule_white.svg +48 -0
  276. chemunited/shared/resources/icons/move_black.svg +4 -0
  277. chemunited/shared/resources/icons/move_white.svg +4 -0
  278. chemunited/shared/resources/icons/offline.svg +28 -0
  279. chemunited/shared/resources/icons/online.svg +25 -0
  280. chemunited/shared/resources/icons/onlineA.svg +22 -0
  281. chemunited/shared/resources/icons/onlineB.svg +23 -0
  282. chemunited/shared/resources/icons/onlineC.svg +24 -0
  283. chemunited/shared/resources/icons/open_folder_black.svg +7 -0
  284. chemunited/shared/resources/icons/open_folder_white.svg +7 -0
  285. chemunited/shared/resources/icons/orchestrator_black.svg +2 -0
  286. chemunited/shared/resources/icons/orchestrator_white.svg +2 -0
  287. chemunited/shared/resources/icons/pause_black.svg +5 -0
  288. chemunited/shared/resources/icons/pause_white.svg +5 -0
  289. chemunited/shared/resources/icons/play_black.svg +14 -0
  290. chemunited/shared/resources/icons/play_white.svg +14 -0
  291. chemunited/shared/resources/icons/process_black.svg +14 -0
  292. chemunited/shared/resources/icons/process_white.svg +14 -0
  293. chemunited/shared/resources/icons/python.svg +1 -0
  294. chemunited/shared/resources/icons/router.svg +28 -0
  295. chemunited/shared/resources/icons/scissor_black.svg +2 -0
  296. chemunited/shared/resources/icons/scissor_white.svg +14 -0
  297. chemunited/shared/resources/icons/select_black.svg +12 -0
  298. chemunited/shared/resources/icons/select_white.svg +12 -0
  299. chemunited/shared/resources/icons/simulation.svg +27 -0
  300. chemunited/shared/resources/icons/slow_black.svg +9 -0
  301. chemunited/shared/resources/icons/slow_white.svg +9 -0
  302. chemunited/shared/resources/icons/speed_black.svg +10 -0
  303. chemunited/shared/resources/icons/speed_white.svg +10 -0
  304. chemunited/shared/resources/icons/status_black.svg +5 -0
  305. chemunited/shared/resources/icons/status_white.svg +5 -0
  306. chemunited/shared/resources/icons/stop_black.svg +10 -0
  307. chemunited/shared/resources/icons/stop_white.svg +10 -0
  308. chemunited/shared/resources/icons/string_black.svg +6 -0
  309. chemunited/shared/resources/icons/string_white.svg +6 -0
  310. chemunited/shared/resources/icons/toml.svg +1 -0
  311. chemunited/shared/resources/icons/trash_black.svg +1 -0
  312. chemunited/shared/resources/icons/trash_white.svg +1 -0
  313. chemunited/shared/resources/icons/update_black.svg +2 -0
  314. chemunited/shared/resources/icons/update_white.svg +2 -0
  315. chemunited/shared/resources/icons/upload_black.svg +7 -0
  316. chemunited/shared/resources/icons/upload_white.svg +7 -0
  317. chemunited/shared/resources/icons/variable_black.svg +12 -0
  318. chemunited/shared/resources/icons/variable_white.svg +12 -0
  319. chemunited/shared/resources/icons/waiting_icon.svg +1 -0
  320. chemunited/shared/resources/icons/water.svg +5 -0
  321. chemunited/shared/resources/icons/wifi_black.svg +6 -0
  322. chemunited/shared/resources/icons/wifi_white.svg +6 -0
  323. chemunited/shared/resources/lexer/theme_dark.json +62 -0
  324. chemunited/shared/resources/lexer/theme_light.json +62 -0
  325. chemunited/shared/resources/qss/dark/loggings_widget.qss +6 -0
  326. chemunited/shared/resources/qss/dark/main_window.qss +21 -0
  327. chemunited/shared/resources/qss/light/loggings_widget.qss +6 -0
  328. chemunited/shared/resources/qss/light/main_window.qss +21 -0
  329. chemunited/shared/resources/resources_rc.py +31195 -0
  330. chemunited/shared/resources/resources_rc.qrc +183 -0
  331. chemunited/shared/resources/scripts/parameter.txt +12 -0
  332. chemunited/shared/resources/scripts/process.txt +139 -0
  333. chemunited/shared/resources/scripts/project.txt +43 -0
  334. chemunited/shared/widgets/__init__.py +0 -0
  335. chemunited/shared/widgets/base_mode_editor/__init__.py +4 -0
  336. chemunited/shared/widgets/base_mode_editor/card_factory.py +95 -0
  337. chemunited/shared/widgets/base_mode_editor/cards/__init__.py +0 -0
  338. chemunited/shared/widgets/base_mode_editor/cards/base_card.py +111 -0
  339. chemunited/shared/widgets/base_mode_editor/cards/bool_card.py +58 -0
  340. chemunited/shared/widgets/base_mode_editor/cards/builder_models.py +251 -0
  341. chemunited/shared/widgets/base_mode_editor/cards/choice_card.py +74 -0
  342. chemunited/shared/widgets/base_mode_editor/cards/float_card.py +73 -0
  343. chemunited/shared/widgets/base_mode_editor/cards/int_card.py +65 -0
  344. chemunited/shared/widgets/base_mode_editor/cards/list_card.py +121 -0
  345. chemunited/shared/widgets/base_mode_editor/cards/quantity_card.py +152 -0
  346. chemunited/shared/widgets/base_mode_editor/cards/str_card.py +50 -0
  347. chemunited/shared/widgets/base_mode_editor/dialog.py +53 -0
  348. chemunited/shared/widgets/base_mode_editor/editor_widget.py +211 -0
  349. chemunited/shared/widgets/base_mode_editor/example.py +251 -0
  350. chemunited/shared/widgets/busy_status.py +79 -0
  351. chemunited/shared/widgets/frame_base.py +293 -0
  352. chemunited/shared/widgets/loggings_widget.py +360 -0
  353. chemunited/shared/widgets/logo_window.py +106 -0
  354. chemunited/shared/widgets/main_window.py +192 -0
  355. chemunited/shared/widgets/segment_widget.py +49 -0
  356. chemunited/simulation/__init__.py +4 -0
  357. chemunited/simulation/final_state.py +297 -0
  358. chemunited/simulation/graph_simulation.py +10 -0
  359. chemunited/simulation/playback.py +61 -0
  360. chemunited/simulation/simulate_report.py +1024 -0
  361. chemunited/utils/files.py +39 -0
  362. chemunited/utils/flowchem_listener.py +176 -0
  363. chemunited/utils/math_functions.py +154 -0
  364. chemunited/utils/update_dialog.py +82 -0
  365. chemunited/utils/version_check.py +45 -0
  366. chemunited-0.0.1.dist-info/METADATA +36 -0
  367. chemunited-0.0.1.dist-info/RECORD +371 -0
  368. chemunited-0.0.1.dist-info/WHEEL +5 -0
  369. chemunited-0.0.1.dist-info/entry_points.txt +2 -0
  370. chemunited-0.0.1.dist-info/licenses/LICENSE +21 -0
  371. chemunited-0.0.1.dist-info/top_level.txt +1 -0
chemunited/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ from .shared.resources import resources_rc
2
+
3
+ __all__ = ["resources_rc"]
chemunited/__main__.py ADDED
@@ -0,0 +1,53 @@
1
+ import sys
2
+ from pathlib import Path
3
+
4
+ import rich_click as click
5
+ from PyQt5.QtCore import Qt, QTimer
6
+ from PyQt5.QtGui import QIcon
7
+ from PyQt5.QtWidgets import QApplication
8
+
9
+ from chemunited.setup import SetupWindow
10
+
11
+ _APP_ID = "org.chemunited.orchestrator"
12
+ _ICON_PATH = ":/icons/icons/chemunited.ico"
13
+
14
+
15
+ @click.command()
16
+ @click.argument("project_file", type=click.Path(exists=True), required=False)
17
+ @click.option(
18
+ "--overwrite",
19
+ is_flag=True,
20
+ default=False,
21
+ help="Overwrite an existing project directory when importing a .chemunited file.",
22
+ )
23
+ def main(project_file: str | None = None, overwrite: bool = False) -> None:
24
+ """Entry point for launching the ChemUnited GUI."""
25
+ if sys.platform == "win32":
26
+ import ctypes
27
+
28
+ ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(_APP_ID)
29
+
30
+ # Set high DPI settings for better display scaling
31
+ QApplication.setHighDpiScaleFactorRoundingPolicy(
32
+ Qt.HighDpiScaleFactorRoundingPolicy.PassThrough # type: ignore[attr-defined]
33
+ )
34
+ QApplication.setAttribute(Qt.AA_EnableHighDpiScaling) # type: ignore[attr-defined]
35
+ QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) # type: ignore[attr-defined]
36
+
37
+ app = QApplication(sys.argv)
38
+
39
+ app.setWindowIcon(QIcon(_ICON_PATH))
40
+
41
+ window = SetupWindow()
42
+ window.show()
43
+ if project_file:
44
+ _path = Path(project_file).resolve()
45
+ _overwrite = overwrite
46
+ QTimer.singleShot(
47
+ 0, lambda: window.orchestrator.open_project(_path, overwrite=_overwrite)
48
+ )
49
+ sys.exit(app.exec_())
50
+
51
+
52
+ if __name__ == "__main__":
53
+ main()
File without changes
@@ -0,0 +1,77 @@
1
+ from typing import TYPE_CHECKING, override
2
+
3
+ from loguru import logger
4
+
5
+ from chemunited.elements.component.graph_item import GraphComponent
6
+ from chemunited.shared.enums import SetupStepMode
7
+ from chemunited.shared.graph import GraphCore, SceneCore
8
+
9
+ from .online_list import OnlineList
10
+
11
+ if TYPE_CHECKING:
12
+ from ..setup import SetupWindow
13
+
14
+
15
+ class ConnectivityGraphicView(GraphCore):
16
+ MODE = SetupStepMode.CONNECTIVITY
17
+
18
+ def __init__(self, scene: SceneCore | None = None, parent=None):
19
+ super().__init__(scene, parent)
20
+ self.setObjectName("ConnectivityGraphicView")
21
+ if parent is not None:
22
+ self.parent_ref: SetupWindow = parent
23
+
24
+ @override
25
+ def dragEnterEvent(self, event):
26
+ if event.mimeData().hasFormat(OnlineList.MIME):
27
+ event.acceptProposedAction()
28
+ else:
29
+ event.ignore()
30
+
31
+ @override
32
+ def dragMoveEvent(self, event):
33
+ if event.mimeData().hasFormat(OnlineList.MIME):
34
+ event.acceptProposedAction()
35
+ else:
36
+ event.ignore()
37
+
38
+ def _component_at_drop_position(self, event) -> GraphComponent | None:
39
+ scene_pos = self.mapToScene(event.pos())
40
+ scene = self.scene()
41
+ if scene is None:
42
+ return None
43
+
44
+ for item in scene.items(scene_pos):
45
+ current = item
46
+ while current is not None:
47
+ if isinstance(current, GraphComponent):
48
+ return current
49
+ current = current.parentItem() # type: ignore[assignment]
50
+ return None
51
+
52
+ @override
53
+ def dropEvent(self, event):
54
+ if not event.mimeData().hasFormat(OnlineList.MIME):
55
+ event.ignore()
56
+ return
57
+
58
+ url_component = event.mimeData().data(OnlineList.MIME).data().decode("utf-8")
59
+ event.acceptProposedAction()
60
+
61
+ component = self._component_at_drop_position(event)
62
+ if component is None:
63
+ logger.warning(
64
+ f"No component found at position {self.mapToScene(event.pos())}"
65
+ )
66
+ return
67
+ if not component.inf.is_electronic:
68
+ logger.warning(f"Component {component.inf.name} is not electronic.")
69
+ return
70
+
71
+ if hasattr(self, "parent_ref"):
72
+ self.parent_ref.orchestrator.associate_component(
73
+ name=component.inf.name,
74
+ urlc=url_component,
75
+ )
76
+ else:
77
+ print(url_component, component.inf.name)
@@ -0,0 +1,364 @@
1
+ from typing import TYPE_CHECKING, Optional
2
+ from urllib.parse import urlsplit, urlunsplit
3
+
4
+ from loguru import logger
5
+ from PyQt5.QtCore import QMimeData, Qt
6
+ from PyQt5.QtGui import QColor, QDrag, QFont, QIcon, QPainter, QPixmap
7
+ from PyQt5.QtWidgets import QHBoxLayout, QLabel, QListWidgetItem, QVBoxLayout, QWidget
8
+ from qfluentwidgets import (
9
+ EditableComboBox,
10
+ FluentIcon,
11
+ ListWidget,
12
+ PushButton,
13
+ StrongBodyLabel,
14
+ TransparentToolButton,
15
+ isDarkTheme,
16
+ )
17
+
18
+ from chemunited.shared.icon import OrchestratorIcon
19
+ from chemunited.utils.flowchem_listener import (
20
+ FLOWCHEM_SERVERS,
21
+ access_url,
22
+ )
23
+
24
+ if TYPE_CHECKING:
25
+ from chemunited.setup import SetupWindow
26
+
27
+
28
+ class OnlineList(ListWidget):
29
+ MIME = "application/x-chemunited-online-list"
30
+
31
+ def __init__(self, api_obj, parent=None):
32
+ super().__init__(parent)
33
+ self.api_obj = api_obj
34
+ self.setDragEnabled(True)
35
+ # Important: allow dragging outside the widget
36
+ self.setDefaultDropAction(Qt.MoveAction) # type: ignore[attr-defined]
37
+
38
+ def startDrag(self, supportedActions):
39
+ item = self.currentItem()
40
+ if item:
41
+ url_c = self.api_obj.currentText() + "/" + item.text()
42
+ mime = QMimeData()
43
+ mime.setData(self.MIME, url_c.encode("utf-8"))
44
+ mime.setText(url_c)
45
+
46
+ drag = QDrag(self)
47
+ drag.setMimeData(mime)
48
+
49
+ # === Create a custom pixmap that shows icon + text ===
50
+ icon = item.icon()
51
+ text = item.text()
52
+
53
+ # Define pixmap size (width can adapt to text length)
54
+ width = max(140, len(text) * 8 + 40)
55
+ height = 36
56
+ pixmap = QPixmap(width, height)
57
+ pixmap.fill(Qt.transparent) # type: ignore[attr-defined]
58
+
59
+ painter = QPainter(pixmap)
60
+
61
+ # Rounded background (light or dark depending on theme)
62
+ bg_color = (
63
+ QColor(40, 40, 40, 180) if isDarkTheme() else QColor(240, 240, 240, 200)
64
+ )
65
+ painter.setRenderHint(QPainter.Antialiasing)
66
+ painter.setBrush(bg_color)
67
+ painter.setPen(Qt.NoPen) # type: ignore[attr-defined]
68
+ painter.drawRoundedRect(0, 0, width, height, 8, 8)
69
+
70
+ # Draw icon
71
+ if not icon.isNull():
72
+ icon_pix = icon.pixmap(24, 24)
73
+ painter.drawPixmap(6, (height - 24) // 2, icon_pix)
74
+
75
+ # Draw text
76
+ painter.setFont(QFont("Segoe UI", 9))
77
+ painter.setPen(
78
+ Qt.white if isDarkTheme() else Qt.black # type: ignore[attr-defined]
79
+ )
80
+ painter.drawText(36, 22, text)
81
+
82
+ painter.end()
83
+
84
+ # Set this custom pixmap as the drag image
85
+ drag.setPixmap(pixmap)
86
+ drag.setHotSpot(pixmap.rect().center())
87
+
88
+ drag.exec_(Qt.CopyAction) # type: ignore[attr-defined]
89
+
90
+
91
+ class OnlineComponent(QWidget):
92
+ def __init__(self, parent):
93
+ super().__init__()
94
+ self._parent: Optional["SetupWindow"] = parent
95
+ layout = QVBoxLayout(self)
96
+
97
+ self.api = EditableComboBox(self)
98
+ self.api.setPlaceholderText("-")
99
+ self.api.currentTextChanged.connect(self.select_api)
100
+ self.api.textEdited.connect(self._on_manual_api_edited)
101
+ self.api.returnPressed.connect(self.submit_manual_api)
102
+ layout.addWidget(StrongBodyLabel("Available Flowchem servers", parent=self))
103
+ layout.addWidget(self.api)
104
+
105
+ self.OnlineList = OnlineList(api_obj=self.api)
106
+ widget = QWidget()
107
+ icon = TransparentToolButton(OrchestratorIcon.MOVE, self)
108
+ icon.setToolTip("Item in the list is movable to the graphic")
109
+ label_text = StrongBodyLabel("Available Online Components", parent=self)
110
+ label_text.setToolTip("Item in the list is movable to the graphic")
111
+ label_layout = QHBoxLayout(widget)
112
+ label_layout.setContentsMargins(0, 0, 0, 0)
113
+ label_layout.addWidget(icon)
114
+ label_layout.addWidget(label_text)
115
+ layout.addWidget(widget)
116
+ layout.addWidget(self.OnlineList)
117
+
118
+ self.LockList = ListWidget()
119
+ layout.addWidget(StrongBodyLabel("Lock Online Components", parent=self))
120
+ layout.addWidget(self.LockList)
121
+
122
+ self.update_button = PushButton(OrchestratorIcon.UPDATE, "Update List", self)
123
+ self.update_button.clicked.connect(self.update_list)
124
+ layout.addWidget(self.update_button)
125
+
126
+ def update_list(self):
127
+ self.update_button.setEnabled(True)
128
+ self.api.clear()
129
+ self.api.setText("")
130
+ FLOWCHEM_SERVERS.update()
131
+ for item in FLOWCHEM_SERVERS.servers:
132
+ self.api.addItem(item)
133
+
134
+ def _on_manual_api_edited(self, _text: str):
135
+ self.update_button.setEnabled(False)
136
+
137
+ def submit_manual_api(self):
138
+ raw_url = self.api.text()
139
+ normalized_url = self._normalize_api_url(raw_url)
140
+ if not normalized_url:
141
+ self._reject_manual_api(
142
+ raw_url,
143
+ normalized_url,
144
+ "Flowchem API address is empty or invalid.",
145
+ )
146
+ return
147
+
148
+ self._show_busy_status(
149
+ "Inspecting FlowChem API",
150
+ f"Reading {normalized_url}/openapi.json...",
151
+ )
152
+ ok, data = access_url(f"{normalized_url}/openapi.json", timeout=1)
153
+ if not ok:
154
+ self._reject_manual_api(
155
+ raw_url,
156
+ normalized_url,
157
+ "Flowchem API is not reachable at {}.",
158
+ normalized_url,
159
+ )
160
+ return
161
+
162
+ if not isinstance(data, dict) or not isinstance(data.get("paths"), dict):
163
+ self._reject_manual_api(
164
+ raw_url,
165
+ normalized_url,
166
+ "Flowchem API at {} does not expose a valid openapi paths object.",
167
+ normalized_url,
168
+ )
169
+ return
170
+
171
+ if "/startup_config" not in data["paths"]:
172
+ self._reject_manual_api(
173
+ raw_url,
174
+ normalized_url,
175
+ "Flowchem API at {} does not expose startup_config. "
176
+ "Update Flowchem for smooth connection with chemunited.",
177
+ normalized_url,
178
+ )
179
+ return
180
+
181
+ FLOWCHEM_SERVERS.register_openapi(normalized_url, data)
182
+ self._select_registered_api(raw_url=raw_url, normalized_url=normalized_url)
183
+ self.update_button.setEnabled(True)
184
+ component_count = sum(
185
+ len(components)
186
+ for components in FLOWCHEM_SERVERS.servers[normalized_url].values()
187
+ )
188
+ self._finish_busy_status(f"Registered {component_count} FlowChem component(s).")
189
+
190
+ @staticmethod
191
+ def _normalize_api_url(raw_url: str) -> str:
192
+ url = raw_url.strip().rstrip("/")
193
+ if not url:
194
+ return ""
195
+
196
+ if "://" not in url:
197
+ url = f"http://{url}"
198
+
199
+ parsed = urlsplit(url)
200
+ if parsed.scheme not in {"http", "https"} or not parsed.netloc:
201
+ return ""
202
+
203
+ path = parsed.path.rstrip("/")
204
+ return urlunsplit((parsed.scheme, parsed.netloc, path, "", ""))
205
+
206
+ def _select_registered_api(self, raw_url: str, normalized_url: str):
207
+ signals_blocked = self.api.blockSignals(True)
208
+ try:
209
+ if raw_url != normalized_url:
210
+ raw_index = self.api.findText(raw_url)
211
+ if raw_index >= 0:
212
+ self.api.removeItem(raw_index)
213
+
214
+ index = self.api.findText(normalized_url)
215
+ if index < 0:
216
+ self.api.addItem(normalized_url)
217
+ index = self.api.findText(normalized_url)
218
+
219
+ self.api.setCurrentIndex(index)
220
+ self.api.setText(normalized_url)
221
+ finally:
222
+ self.api.blockSignals(signals_blocked)
223
+
224
+ self.select_api(normalized_url)
225
+
226
+ def _reject_manual_api(
227
+ self, raw_url: str, normalized_url: str, message: str, *args
228
+ ):
229
+ self.OnlineList.clear()
230
+ self._remove_unregistered_api_items(raw_url, normalized_url)
231
+ self.api.setText(raw_url)
232
+ self.update_button.setEnabled(True)
233
+ formatted = message.format(*args) if args else message
234
+ self._fail_busy_status(formatted)
235
+ logger.warning(message, *args)
236
+
237
+ def _show_busy_status(self, title: str, message: str) -> None:
238
+ if self._parent is None:
239
+ return
240
+ show_busy_status = getattr(self._parent, "show_busy_status", None)
241
+ if callable(show_busy_status):
242
+ show_busy_status(title, message)
243
+
244
+ def _finish_busy_status(self, message: str) -> None:
245
+ if self._parent is None:
246
+ return
247
+ finish_busy_status = getattr(self._parent, "finish_busy_status", None)
248
+ if callable(finish_busy_status):
249
+ finish_busy_status(message)
250
+
251
+ def _fail_busy_status(self, message: str) -> None:
252
+ if self._parent is None:
253
+ return
254
+ fail_busy_status = getattr(self._parent, "fail_busy_status", None)
255
+ if callable(fail_busy_status):
256
+ fail_busy_status(message)
257
+
258
+ def _remove_unregistered_api_items(self, *urls: str):
259
+ for url in dict.fromkeys(urls):
260
+ if not url or url in FLOWCHEM_SERVERS.servers:
261
+ continue
262
+
263
+ index = self.api.findText(url)
264
+ if index >= 0:
265
+ self.api.removeItem(index)
266
+
267
+ def select_api(self, item):
268
+ url = item.rstrip("/")
269
+ self.OnlineList.clear()
270
+
271
+ if url in FLOWCHEM_SERVERS.servers:
272
+ for device in FLOWCHEM_SERVERS.servers[url]:
273
+ for component in FLOWCHEM_SERVERS.servers[url][device]:
274
+ urlc = f"{url}/{device}/{component}"
275
+ figure = OrchestratorIcon.COMPONENT_ICON.path()
276
+
277
+ # Create the list item with icon + text
278
+ text = f"{device}/{component}"
279
+ list_item = QListWidgetItem(QIcon(figure), text)
280
+ self.OnlineList.addItem(list_item)
281
+
282
+ list_item.setToolTip(f"{text}\nDiscovered from openapi.json")
283
+
284
+ used_by = self._component_using_url(urlc)
285
+ if used_by is not None:
286
+ self.add_to_lock(text, QIcon(figure), used_by)
287
+ self.OnlineList.takeItem(self.OnlineList.row(list_item))
288
+
289
+ def associate_item(self, component: str, text: str | None = None):
290
+ """Move selected items from OnlineList to LockList."""
291
+ if text:
292
+ for i in range(self.OnlineList.count()):
293
+ item = self.OnlineList.item(i)
294
+ if item.text() == text:
295
+ self.add_to_lock(item.text(), item.icon(), component)
296
+ self.OnlineList.takeItem(i)
297
+ return
298
+ else:
299
+ for item in self.OnlineList.selectedItems():
300
+ self.add_to_lock(item.text(), item.icon(), component)
301
+ self.OnlineList.takeItem(self.OnlineList.row(item))
302
+
303
+ def add_to_lock(self, text, icon, component):
304
+ """Add QListWidgetItem to B, with icon + button."""
305
+ item = QListWidgetItem(icon, text)
306
+ self.LockList.addItem(item)
307
+
308
+ # Create small widget with label + button
309
+ widget = QWidget()
310
+ layout = QHBoxLayout(widget)
311
+ layout.setContentsMargins(4, 0, 4, 0)
312
+
313
+ label = QLabel(text)
314
+ label.setVisible(False)
315
+ button = TransparentToolButton(FluentIcon.CANCEL_MEDIUM, self)
316
+ button.setToolTip("Disconnect component")
317
+ button.clicked.connect(
318
+ lambda _, t=text, ic=icon: self.move_back_to_online(t, ic, component)
319
+ )
320
+
321
+ layout.addWidget(label)
322
+ layout.addStretch()
323
+ layout.addWidget(button)
324
+
325
+ item.setSizeHint(widget.sizeHint())
326
+ self.LockList.setItemWidget(item, widget)
327
+
328
+ def move_back_to_online(self, text, icon, component):
329
+ """Move the item back from LockList to OnlineList."""
330
+ for i in range(self.LockList.count()):
331
+ item = self.LockList.item(i)
332
+ widget = self.LockList.itemWidget(item)
333
+ if widget:
334
+ label = widget.findChild(QLabel)
335
+ if label and label.text() == text:
336
+ if self._parent:
337
+ self._parent.orchestrator.disassociate_component(component)
338
+ self.LockList.takeItem(i)
339
+ break
340
+ self.OnlineList.addItem(QListWidgetItem(icon, text))
341
+
342
+ def _component_using_url(self, urlc: str) -> str | None:
343
+ if not self._parent:
344
+ return None
345
+
346
+ target_url = urlc.rstrip("/")
347
+ for component in self._parent.orchestrator.components.values():
348
+ if not component.inf.is_electronic:
349
+ continue
350
+ if str(component.url).rstrip("/") == target_url:
351
+ return component.name
352
+ return None
353
+
354
+
355
+ if __name__ == "__main__":
356
+ import sys
357
+
358
+ from PyQt5.QtWidgets import QApplication
359
+
360
+ app = QApplication(sys.argv)
361
+ w = OnlineComponent(parent=None)
362
+ w.update_list()
363
+ w.show()
364
+ sys.exit(app.exec_())