cgse 2024.7.0__py3-none-any.whl → 2025.0.2__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 (664) hide show
  1. README.md +27 -0
  2. bump.py +85 -0
  3. cgse-2025.0.2.dist-info/METADATA +38 -0
  4. cgse-2025.0.2.dist-info/RECORD +5 -0
  5. {cgse-2024.7.0.dist-info → cgse-2025.0.2.dist-info}/WHEEL +1 -2
  6. cgse-2024.7.0.dist-info/COPYING +0 -674
  7. cgse-2024.7.0.dist-info/COPYING.LESSER +0 -165
  8. cgse-2024.7.0.dist-info/METADATA +0 -144
  9. cgse-2024.7.0.dist-info/RECORD +0 -660
  10. cgse-2024.7.0.dist-info/entry_points.txt +0 -75
  11. cgse-2024.7.0.dist-info/top_level.txt +0 -2
  12. egse/__init__.py +0 -12
  13. egse/__main__.py +0 -32
  14. egse/aeu/aeu.py +0 -5238
  15. egse/aeu/aeu_awg.yaml +0 -265
  16. egse/aeu/aeu_crio.yaml +0 -273
  17. egse/aeu/aeu_cs.py +0 -627
  18. egse/aeu/aeu_devif.py +0 -321
  19. egse/aeu/aeu_main_ui.py +0 -903
  20. egse/aeu/aeu_metrics.py +0 -131
  21. egse/aeu/aeu_protocol.py +0 -463
  22. egse/aeu/aeu_psu.yaml +0 -204
  23. egse/aeu/aeu_ui.py +0 -873
  24. egse/aeu/arbdata/FccdRead.arb +0 -2
  25. egse/aeu/arbdata/FccdRead_min_points.arb +0 -2
  26. egse/aeu/arbdata/HeaterSync_FccdRead.arb +0 -2
  27. egse/aeu/arbdata/HeaterSync_ccdRead25.arb +0 -2
  28. egse/aeu/arbdata/HeaterSync_ccdRead31_25.arb +0 -2
  29. egse/aeu/arbdata/HeaterSync_ccdRead37_50.arb +0 -2
  30. egse/aeu/arbdata/HeaterSync_ccdRead43_75.arb +0 -2
  31. egse/aeu/arbdata/HeaterSync_ccdRead50.arb +0 -2
  32. egse/aeu/arbdata/Heater_FccdRead_min_points.arb +0 -2
  33. egse/aeu/arbdata/ccdRead25.arb +0 -2
  34. egse/aeu/arbdata/ccdRead25_150ms.arb +0 -2
  35. egse/aeu/arbdata/ccdRead31_25.arb +0 -2
  36. egse/aeu/arbdata/ccdRead31_25_150ms.arb +0 -2
  37. egse/aeu/arbdata/ccdRead37_50.arb +0 -2
  38. egse/aeu/arbdata/ccdRead37_50_150ms.arb +0 -2
  39. egse/aeu/arbdata/ccdRead43_75.arb +0 -2
  40. egse/aeu/arbdata/ccdRead43_75_150ms.arb +0 -2
  41. egse/aeu/arbdata/ccdRead50.arb +0 -2
  42. egse/aeu/arbdata/ccdRead50_150ms.arb +0 -2
  43. egse/alert/__init__.py +0 -1049
  44. egse/alert/alertman.yaml +0 -37
  45. egse/alert/alertman_cs.py +0 -233
  46. egse/alert/alertman_ui.py +0 -600
  47. egse/alert/gsm/beaglebone.py +0 -138
  48. egse/alert/gsm/beaglebone.yaml +0 -51
  49. egse/alert/gsm/beaglebone_cs.py +0 -108
  50. egse/alert/gsm/beaglebone_devif.py +0 -122
  51. egse/alert/gsm/beaglebone_protocol.py +0 -46
  52. egse/bits.py +0 -318
  53. egse/camera.py +0 -44
  54. egse/collimator/__init__.py +0 -0
  55. egse/collimator/fcul/__init__.py +0 -0
  56. egse/collimator/fcul/ogse.py +0 -1077
  57. egse/collimator/fcul/ogse.yaml +0 -14
  58. egse/collimator/fcul/ogse_cs.py +0 -154
  59. egse/collimator/fcul/ogse_devif.py +0 -358
  60. egse/collimator/fcul/ogse_protocol.py +0 -132
  61. egse/collimator/fcul/ogse_sim.py +0 -431
  62. egse/collimator/fcul/ogse_ui.py +0 -1108
  63. egse/command.py +0 -699
  64. egse/config.py +0 -410
  65. egse/confman/__init__.py +0 -1058
  66. egse/confman/confman.yaml +0 -70
  67. egse/confman/confman_cs.py +0 -240
  68. egse/confman/confman_ui.py +0 -381
  69. egse/confman/setup_ui.py +0 -565
  70. egse/control.py +0 -632
  71. egse/coordinates/__init__.py +0 -534
  72. egse/coordinates/avoidance.py +0 -100
  73. egse/coordinates/cslmodel.py +0 -127
  74. egse/coordinates/laser_tracker_to_dict.py +0 -122
  75. egse/coordinates/point.py +0 -707
  76. egse/coordinates/pyplot.py +0 -194
  77. egse/coordinates/referenceFrame.py +0 -1279
  78. egse/coordinates/refmodel.py +0 -737
  79. egse/coordinates/rotationMatrix.py +0 -85
  80. egse/coordinates/transform3d_addon.py +0 -419
  81. egse/csl/__init__.py +0 -50
  82. egse/csl/commanding.py +0 -78
  83. egse/csl/icons/hexapod-connected-selected.svg +0 -30
  84. egse/csl/icons/hexapod-connected.svg +0 -30
  85. egse/csl/icons/hexapod-homing-selected.svg +0 -68
  86. egse/csl/icons/hexapod-homing.svg +0 -68
  87. egse/csl/icons/hexapod-retract-selected.svg +0 -56
  88. egse/csl/icons/hexapod-retract.svg +0 -51
  89. egse/csl/icons/hexapod-zero-selected.svg +0 -56
  90. egse/csl/icons/hexapod-zero.svg +0 -56
  91. egse/csl/icons/logo-puna.svg +0 -92
  92. egse/csl/icons/stop.svg +0 -1
  93. egse/csl/initialisation.py +0 -102
  94. egse/csl/mech_pos_settings.yaml +0 -18
  95. egse/das.py +0 -1240
  96. egse/das.yaml +0 -7
  97. egse/data/conf/SETUP_CSL_00000_170620_150000.yaml +0 -5
  98. egse/data/conf/SETUP_CSL_00001_170620_151010.yaml +0 -69
  99. egse/data/conf/SETUP_CSL_00002_170620_151020.yaml +0 -69
  100. egse/data/conf/SETUP_CSL_00003_170620_151030.yaml +0 -69
  101. egse/data/conf/SETUP_CSL_00004_170620_151040.yaml +0 -69
  102. egse/data/conf/SETUP_CSL_00005_170620_151050.yaml +0 -69
  103. egse/data/conf/SETUP_CSL_00006_170620_151060.yaml +0 -69
  104. egse/data/conf/SETUP_CSL_00007_170620_151070.yaml +0 -69
  105. egse/data/conf/SETUP_CSL_00008_170620_151080.yaml +0 -75
  106. egse/data/conf/SETUP_CSL_00010_210308_083016.yaml +0 -138
  107. egse/data/conf/SETUP_INTA_00000_170620_150000.yaml +0 -4
  108. egse/data/conf/SETUP_SRON_00000_170620_150000.yaml +0 -4
  109. egse/decorators.py +0 -514
  110. egse/device.py +0 -269
  111. egse/dpu/__init__.py +0 -2698
  112. egse/dpu/ccd_ui.py +0 -514
  113. egse/dpu/dpu.py +0 -783
  114. egse/dpu/dpu.yaml +0 -153
  115. egse/dpu/dpu_cs.py +0 -272
  116. egse/dpu/dpu_ui.py +0 -671
  117. egse/dpu/fitsgen.py +0 -2096
  118. egse/dpu/fitsgen_ui.py +0 -399
  119. egse/dpu/hdf5_model.py +0 -332
  120. egse/dpu/hdf5_ui.py +0 -277
  121. egse/dpu/hdf5_viewer.py +0 -506
  122. egse/dpu/hk_ui.py +0 -468
  123. egse/dpu_commands.py +0 -81
  124. egse/dsi/__init__.py +0 -33
  125. egse/dsi/_libesl.py +0 -232
  126. egse/dsi/constants.py +0 -296
  127. egse/dsi/esl.py +0 -630
  128. egse/dsi/rmap.py +0 -444
  129. egse/dsi/rmapci.py +0 -39
  130. egse/dsi/spw.py +0 -335
  131. egse/dsi/spw_state.py +0 -29
  132. egse/dummy.py +0 -318
  133. egse/dyndummy.py +0 -179
  134. egse/env.py +0 -278
  135. egse/exceptions.py +0 -88
  136. egse/fdir/__init__.py +0 -26
  137. egse/fdir/fdir_manager.py +0 -85
  138. egse/fdir/fdir_manager.yaml +0 -37
  139. egse/fdir/fdir_manager_controller.py +0 -136
  140. egse/fdir/fdir_manager_cs.py +0 -164
  141. egse/fdir/fdir_manager_interface.py +0 -15
  142. egse/fdir/fdir_remote.py +0 -73
  143. egse/fdir/fdir_remote.yaml +0 -30
  144. egse/fdir/fdir_remote_controller.py +0 -30
  145. egse/fdir/fdir_remote_cs.py +0 -94
  146. egse/fdir/fdir_remote_interface.py +0 -9
  147. egse/fdir/fdir_remote_popup.py +0 -26
  148. egse/fee/__init__.py +0 -106
  149. egse/fee/f_fee_register.yaml +0 -43
  150. egse/fee/feesim.py +0 -914
  151. egse/fee/n_fee_hk.py +0 -768
  152. egse/fee/nfee.py +0 -188
  153. egse/filterwheel/__init__.py +0 -4
  154. egse/filterwheel/eksma/__init__.py +0 -49
  155. egse/filterwheel/eksma/fw8smc4.py +0 -657
  156. egse/filterwheel/eksma/fw8smc4.yaml +0 -121
  157. egse/filterwheel/eksma/fw8smc4_cs.py +0 -144
  158. egse/filterwheel/eksma/fw8smc4_devif.py +0 -473
  159. egse/filterwheel/eksma/fw8smc4_protocol.py +0 -82
  160. egse/filterwheel/eksma/fw8smc4_ui.py +0 -940
  161. egse/filterwheel/eksma/fw8smc5.py +0 -115
  162. egse/filterwheel/eksma/fw8smc5.yaml +0 -105
  163. egse/filterwheel/eksma/fw8smc5_controller.py +0 -307
  164. egse/filterwheel/eksma/fw8smc5_cs.py +0 -141
  165. egse/filterwheel/eksma/fw8smc5_interface.py +0 -65
  166. egse/filterwheel/eksma/fw8smc5_simulator.py +0 -29
  167. egse/filterwheel/eksma/fw8smc5_ui.py +0 -1065
  168. egse/filterwheel/eksma/testpythonfw.py +0 -215
  169. egse/fov/__init__.py +0 -65
  170. egse/fov/fov_hk.py +0 -710
  171. egse/fov/fov_ui.py +0 -859
  172. egse/fov/fov_ui_controller.py +0 -140
  173. egse/fov/fov_ui_model.py +0 -200
  174. egse/fov/fov_ui_view.py +0 -345
  175. egse/gimbal/__init__.py +0 -32
  176. egse/gimbal/symetrie/__init__.py +0 -26
  177. egse/gimbal/symetrie/alpha.py +0 -586
  178. egse/gimbal/symetrie/generic_gimbal_ui.py +0 -1521
  179. egse/gimbal/symetrie/gimbal.py +0 -877
  180. egse/gimbal/symetrie/gimbal.yaml +0 -168
  181. egse/gimbal/symetrie/gimbal_cs.py +0 -183
  182. egse/gimbal/symetrie/gimbal_protocol.py +0 -138
  183. egse/gimbal/symetrie/gimbal_ui.py +0 -361
  184. egse/gimbal/symetrie/pmac.py +0 -1006
  185. egse/gimbal/symetrie/pmac_regex.py +0 -83
  186. egse/graph.py +0 -132
  187. egse/gui/__init__.py +0 -47
  188. egse/gui/buttons.py +0 -378
  189. egse/gui/focalplane.py +0 -1285
  190. egse/gui/formatter.py +0 -10
  191. egse/gui/led.py +0 -162
  192. egse/gui/limitswitch.py +0 -143
  193. egse/gui/mechanisms.py +0 -587
  194. egse/gui/states.py +0 -148
  195. egse/gui/stripchart.py +0 -729
  196. egse/gui/styles.qss +0 -48
  197. egse/gui/switch.py +0 -112
  198. egse/h5.py +0 -274
  199. egse/help/__init__.py +0 -0
  200. egse/help/help_ui.py +0 -126
  201. egse/hexapod/__init__.py +0 -32
  202. egse/hexapod/symetrie/__init__.py +0 -137
  203. egse/hexapod/symetrie/alpha.py +0 -874
  204. egse/hexapod/symetrie/dynalpha.py +0 -1387
  205. egse/hexapod/symetrie/hexapod_ui.py +0 -1516
  206. egse/hexapod/symetrie/pmac.py +0 -1010
  207. egse/hexapod/symetrie/pmac_regex.py +0 -83
  208. egse/hexapod/symetrie/puna.py +0 -1167
  209. egse/hexapod/symetrie/puna.yaml +0 -193
  210. egse/hexapod/symetrie/puna_cs.py +0 -195
  211. egse/hexapod/symetrie/puna_protocol.py +0 -134
  212. egse/hexapod/symetrie/puna_ui.py +0 -433
  213. egse/hexapod/symetrie/punaplus.py +0 -107
  214. egse/hexapod/symetrie/zonda.py +0 -872
  215. egse/hexapod/symetrie/zonda.yaml +0 -337
  216. egse/hexapod/symetrie/zonda_cs.py +0 -172
  217. egse/hexapod/symetrie/zonda_devif.py +0 -414
  218. egse/hexapod/symetrie/zonda_protocol.py +0 -123
  219. egse/hexapod/symetrie/zonda_ui.py +0 -449
  220. egse/hk.py +0 -791
  221. egse/icons/aeu-cs-start.svg +0 -117
  222. egse/icons/aeu-cs-stop.svg +0 -118
  223. egse/icons/aeu-cs.svg +0 -107
  224. egse/icons/aeu_cs-started.svg +0 -112
  225. egse/icons/aeu_cs-stopped.svg +0 -112
  226. egse/icons/aeu_cs.svg +0 -55
  227. egse/icons/alert.svg +0 -1
  228. egse/icons/arrow-double-left.png +0 -0
  229. egse/icons/arrow-double-right.png +0 -0
  230. egse/icons/arrow-up.svg +0 -11
  231. egse/icons/backward.svg +0 -1
  232. egse/icons/busy.svg +0 -1
  233. egse/icons/cleaning.svg +0 -115
  234. egse/icons/color-scheme.svg +0 -1
  235. egse/icons/cs-connected-alert.svg +0 -91
  236. egse/icons/cs-connected-disabled.svg +0 -43
  237. egse/icons/cs-connected.svg +0 -89
  238. egse/icons/cs-not-connected.svg +0 -44
  239. egse/icons/double-left-arrow.svg +0 -1
  240. egse/icons/double-right-arrow.svg +0 -1
  241. egse/icons/erase-disabled.svg +0 -19
  242. egse/icons/erase.svg +0 -59
  243. egse/icons/fitsgen-start.svg +0 -47
  244. egse/icons/fitsgen-stop.svg +0 -48
  245. egse/icons/fitsgen.svg +0 -1
  246. egse/icons/forward.svg +0 -1
  247. egse/icons/fov-hk-start.svg +0 -33
  248. egse/icons/fov-hk-stop.svg +0 -37
  249. egse/icons/fov-hk.svg +0 -1
  250. egse/icons/front-desk.svg +0 -1
  251. egse/icons/home-actioned.svg +0 -15
  252. egse/icons/home-disabled.svg +0 -15
  253. egse/icons/home.svg +0 -13
  254. egse/icons/info.svg +0 -1
  255. egse/icons/invalid.png +0 -0
  256. egse/icons/led-green.svg +0 -20
  257. egse/icons/led-grey.svg +0 -20
  258. egse/icons/led-orange.svg +0 -20
  259. egse/icons/led-red.svg +0 -20
  260. egse/icons/led-square-green.svg +0 -134
  261. egse/icons/led-square-grey.svg +0 -134
  262. egse/icons/led-square-orange.svg +0 -134
  263. egse/icons/led-square-red.svg +0 -134
  264. egse/icons/limit-switch-all-green.svg +0 -115
  265. egse/icons/limit-switch-all-red.svg +0 -117
  266. egse/icons/limit-switch-el+.svg +0 -116
  267. egse/icons/limit-switch-el-.svg +0 -117
  268. egse/icons/location-marker.svg +0 -1
  269. egse/icons/logo-dpu.svg +0 -48
  270. egse/icons/logo-gimbal.svg +0 -112
  271. egse/icons/logo-huber.svg +0 -23
  272. egse/icons/logo-ogse.svg +0 -31
  273. egse/icons/logo-puna.svg +0 -92
  274. egse/icons/logo-tcs.svg +0 -29
  275. egse/icons/logo-zonda.svg +0 -66
  276. egse/icons/maximize.svg +0 -1
  277. egse/icons/meter.svg +0 -1
  278. egse/icons/more.svg +0 -45
  279. egse/icons/n-fee-hk-start.svg +0 -24
  280. egse/icons/n-fee-hk-stop.svg +0 -25
  281. egse/icons/n-fee-hk.svg +0 -83
  282. egse/icons/observing-off.svg +0 -46
  283. egse/icons/observing-on.svg +0 -46
  284. egse/icons/open-document-hdf5.png +0 -0
  285. egse/icons/open-document-hdf5.svg +0 -21
  286. egse/icons/ops-mode.svg +0 -1
  287. egse/icons/play-green.svg +0 -17
  288. egse/icons/plugged-disabled.svg +0 -27
  289. egse/icons/plugged.svg +0 -21
  290. egse/icons/pm_ui.svg +0 -1
  291. egse/icons/power-button-green.svg +0 -27
  292. egse/icons/power-button-red.svg +0 -27
  293. egse/icons/power-button.svg +0 -27
  294. egse/icons/radar.svg +0 -1
  295. egse/icons/radioactive.svg +0 -2
  296. egse/icons/reload.svg +0 -1
  297. egse/icons/remote-control-off.svg +0 -28
  298. egse/icons/remote-control-on.svg +0 -28
  299. egse/icons/repeat-blue.svg +0 -15
  300. egse/icons/repeat.svg +0 -1
  301. egse/icons/settings.svg +0 -1
  302. egse/icons/shrink.svg +0 -1
  303. egse/icons/shutter.svg +0 -1
  304. egse/icons/sign-off.svg +0 -1
  305. egse/icons/sign-on.svg +0 -1
  306. egse/icons/sim-mode.svg +0 -1
  307. egse/icons/small-buttons-go.svg +0 -20
  308. egse/icons/small-buttons-minus.svg +0 -51
  309. egse/icons/small-buttons-plus.svg +0 -51
  310. egse/icons/sponge.svg +0 -220
  311. egse/icons/start-button-disabled.svg +0 -84
  312. egse/icons/start-button.svg +0 -50
  313. egse/icons/stop-button-disabled.svg +0 -84
  314. egse/icons/stop-button.svg +0 -50
  315. egse/icons/stop-red.svg +0 -17
  316. egse/icons/stop.svg +0 -1
  317. egse/icons/switch-disabled-square.svg +0 -87
  318. egse/icons/switch-disabled.svg +0 -15
  319. egse/icons/switch-off-square.svg +0 -87
  320. egse/icons/switch-off.svg +0 -72
  321. egse/icons/switch-on-square.svg +0 -87
  322. egse/icons/switch-on.svg +0 -61
  323. egse/icons/temperature-control.svg +0 -44
  324. egse/icons/th_ui_logo.svg +0 -1
  325. egse/icons/unplugged.svg +0 -23
  326. egse/icons/unvalid.png +0 -0
  327. egse/icons/user-interface.svg +0 -1
  328. egse/icons/vacuum.svg +0 -1
  329. egse/icons/valid.png +0 -0
  330. egse/icons/zoom-to-pixel-dark.svg +0 -64
  331. egse/icons/zoom-to-pixel-white.svg +0 -36
  332. egse/images/big-rotation-stage.png +0 -0
  333. egse/images/connected-100.png +0 -0
  334. egse/images/cross.svg +0 -6
  335. egse/images/disconnected-100.png +0 -0
  336. egse/images/gui-icon.png +0 -0
  337. egse/images/home.svg +0 -6
  338. egse/images/info-icon.png +0 -0
  339. egse/images/led-black.svg +0 -89
  340. egse/images/led-green.svg +0 -85
  341. egse/images/led-orange.svg +0 -85
  342. egse/images/led-red.svg +0 -85
  343. egse/images/load-icon.png +0 -0
  344. egse/images/load-setup.png +0 -0
  345. egse/images/load.png +0 -0
  346. egse/images/pause.png +0 -0
  347. egse/images/play-button.svg +0 -8
  348. egse/images/play.png +0 -0
  349. egse/images/process-status.png +0 -0
  350. egse/images/restart.png +0 -0
  351. egse/images/search.png +0 -0
  352. egse/images/sma.png +0 -0
  353. egse/images/start.png +0 -0
  354. egse/images/stop-button.svg +0 -8
  355. egse/images/stop.png +0 -0
  356. egse/images/switch-off.svg +0 -48
  357. egse/images/switch-on.svg +0 -48
  358. egse/images/undo.png +0 -0
  359. egse/images/update-button.svg +0 -11
  360. egse/imageviewer/exposureselection.py +0 -475
  361. egse/imageviewer/imageviewer.py +0 -198
  362. egse/imageviewer/matchfocalplane.py +0 -179
  363. egse/imageviewer/subfieldposition.py +0 -133
  364. egse/lampcontrol/__init__.py +0 -4
  365. egse/lampcontrol/beaglebone/beaglebone.py +0 -178
  366. egse/lampcontrol/beaglebone/beaglebone.yaml +0 -62
  367. egse/lampcontrol/beaglebone/beaglebone_cs.py +0 -106
  368. egse/lampcontrol/beaglebone/beaglebone_devif.py +0 -150
  369. egse/lampcontrol/beaglebone/beaglebone_protocol.py +0 -73
  370. egse/lampcontrol/energetiq/__init__.py +0 -22
  371. egse/lampcontrol/energetiq/eq99.yaml +0 -98
  372. egse/lampcontrol/energetiq/lampEQ99.py +0 -283
  373. egse/lampcontrol/energetiq/lampEQ99_cs.py +0 -128
  374. egse/lampcontrol/energetiq/lampEQ99_devif.py +0 -158
  375. egse/lampcontrol/energetiq/lampEQ99_encode_decode_errors.py +0 -73
  376. egse/lampcontrol/energetiq/lampEQ99_protocol.py +0 -71
  377. egse/lampcontrol/energetiq/lampEQ99_ui.py +0 -465
  378. egse/lib/CentOS-7/EtherSpaceLink_v34_86.dylib +0 -0
  379. egse/lib/CentOS-8/ESL-RMAP_v34_86.dylib +0 -0
  380. egse/lib/CentOS-8/EtherSpaceLink_v34_86.dylib +0 -0
  381. egse/lib/Debian/ESL-RMAP_v34_86.dylib +0 -0
  382. egse/lib/Debian/EtherSpaceLink_v34_86.dylib +0 -0
  383. egse/lib/Debian/libetherspacelink_v35_21.dylib +0 -0
  384. egse/lib/Linux/ESL-RMAP_v34_86.dylib +0 -0
  385. egse/lib/Linux/EtherSpaceLink_v34_86.dylib +0 -0
  386. egse/lib/Ubuntu-20/ESL-RMAP_v34_86.dylib +0 -0
  387. egse/lib/Ubuntu-20/EtherSpaceLink_v34_86.dylib +0 -0
  388. egse/lib/gssw/python3-gssw_2.2.3+31f63c9f-1_all.deb +0 -0
  389. egse/lib/ximc/__pycache__/pyximc.cpython-38 2.pyc +0 -0
  390. egse/lib/ximc/__pycache__/pyximc.cpython-38.pyc +0 -0
  391. egse/lib/ximc/libximc.framework/Frameworks/libbindy.dylib +0 -0
  392. egse/lib/ximc/libximc.framework/Frameworks/libxiwrapper.dylib +0 -0
  393. egse/lib/ximc/libximc.framework/Headers/ximc.h +0 -5510
  394. egse/lib/ximc/libximc.framework/Resources/Info.plist +0 -42
  395. egse/lib/ximc/libximc.framework/Resources/keyfile.sqlite +0 -0
  396. egse/lib/ximc/libximc.framework/libbindy.so +0 -0
  397. egse/lib/ximc/libximc.framework/libximc +0 -0
  398. egse/lib/ximc/libximc.framework/libximc.so +0 -0
  399. egse/lib/ximc/libximc.framework/libximc.so.7.0.0 +0 -0
  400. egse/lib/ximc/libximc.framework/libxiwrapper.so +0 -0
  401. egse/lib/ximc/pyximc.py +0 -922
  402. egse/listener.py +0 -179
  403. egse/logger/__init__.py +0 -243
  404. egse/logger/log_cs.py +0 -321
  405. egse/metrics.py +0 -102
  406. egse/mixin.py +0 -464
  407. egse/monitoring.py +0 -95
  408. egse/ni/alarms/__init__.py +0 -26
  409. egse/ni/alarms/cdaq9375.py +0 -300
  410. egse/ni/alarms/cdaq9375.yaml +0 -89
  411. egse/ni/alarms/cdaq9375_cs.py +0 -130
  412. egse/ni/alarms/cdaq9375_devif.py +0 -183
  413. egse/ni/alarms/cdaq9375_protocol.py +0 -48
  414. egse/obs_inspection.py +0 -165
  415. egse/observer.py +0 -41
  416. egse/obsid.py +0 -163
  417. egse/powermeter/__init__.py +0 -0
  418. egse/powermeter/ni/__init__.py +0 -38
  419. egse/powermeter/ni/cdaq9184.py +0 -224
  420. egse/powermeter/ni/cdaq9184.yaml +0 -73
  421. egse/powermeter/ni/cdaq9184_cs.py +0 -130
  422. egse/powermeter/ni/cdaq9184_devif.py +0 -201
  423. egse/powermeter/ni/cdaq9184_protocol.py +0 -48
  424. egse/powermeter/ni/cdaq9184_ui.py +0 -544
  425. egse/powermeter/thorlabs/__init__.py +0 -25
  426. egse/powermeter/thorlabs/pm100a.py +0 -380
  427. egse/powermeter/thorlabs/pm100a.yaml +0 -132
  428. egse/powermeter/thorlabs/pm100a_cs.py +0 -136
  429. egse/powermeter/thorlabs/pm100a_devif.py +0 -127
  430. egse/powermeter/thorlabs/pm100a_protocol.py +0 -80
  431. egse/powermeter/thorlabs/pm100a_ui.py +0 -725
  432. egse/process.py +0 -451
  433. egse/procman/__init__.py +0 -834
  434. egse/procman/cannot_start_process_popup.py +0 -43
  435. egse/procman/procman.yaml +0 -49
  436. egse/procman/procman_cs.py +0 -201
  437. egse/procman/procman_ui.py +0 -2081
  438. egse/protocol.py +0 -605
  439. egse/proxy.py +0 -531
  440. egse/randomwalk.py +0 -140
  441. egse/reg.py +0 -585
  442. egse/reload.py +0 -122
  443. egse/reprocess.py +0 -693
  444. egse/resource.py +0 -333
  445. egse/rmap.py +0 -406
  446. egse/rst.py +0 -135
  447. egse/search.py +0 -182
  448. egse/serialdevice.py +0 -190
  449. egse/services.py +0 -247
  450. egse/services.yaml +0 -68
  451. egse/settings.py +0 -379
  452. egse/settings.yaml +0 -980
  453. egse/setup.py +0 -1181
  454. egse/shutter/__init__.py +0 -0
  455. egse/shutter/thorlabs/__init__.py +0 -19
  456. egse/shutter/thorlabs/ksc101.py +0 -205
  457. egse/shutter/thorlabs/ksc101.yaml +0 -105
  458. egse/shutter/thorlabs/ksc101_cs.py +0 -136
  459. egse/shutter/thorlabs/ksc101_devif.py +0 -201
  460. egse/shutter/thorlabs/ksc101_protocol.py +0 -71
  461. egse/shutter/thorlabs/ksc101_ui.py +0 -548
  462. egse/shutter/thorlabs/sc10.py +0 -82
  463. egse/shutter/thorlabs/sc10.yaml +0 -52
  464. egse/shutter/thorlabs/sc10_controller.py +0 -81
  465. egse/shutter/thorlabs/sc10_cs.py +0 -108
  466. egse/shutter/thorlabs/sc10_interface.py +0 -25
  467. egse/shutter/thorlabs/sc10_simulator.py +0 -30
  468. egse/simulator.py +0 -41
  469. egse/slack.py +0 -61
  470. egse/socketdevice.py +0 -218
  471. egse/sockets.py +0 -218
  472. egse/spw.py +0 -1401
  473. egse/stages/__init__.py +0 -12
  474. egse/stages/aerotech/ensemble.py +0 -245
  475. egse/stages/aerotech/ensemble.yaml +0 -205
  476. egse/stages/aerotech/ensemble_controller.py +0 -275
  477. egse/stages/aerotech/ensemble_cs.py +0 -110
  478. egse/stages/aerotech/ensemble_interface.py +0 -132
  479. egse/stages/aerotech/ensemble_parameters.py +0 -433
  480. egse/stages/aerotech/ensemble_simulator.py +0 -27
  481. egse/stages/aerotech/mgse_sim.py +0 -188
  482. egse/stages/arun/smd3.py +0 -110
  483. egse/stages/arun/smd3.yaml +0 -68
  484. egse/stages/arun/smd3_controller.py +0 -470
  485. egse/stages/arun/smd3_cs.py +0 -112
  486. egse/stages/arun/smd3_interface.py +0 -53
  487. egse/stages/arun/smd3_simulator.py +0 -27
  488. egse/stages/arun/smd3_stop.py +0 -16
  489. egse/stages/huber/__init__.py +0 -49
  490. egse/stages/huber/smc9300.py +0 -920
  491. egse/stages/huber/smc9300.yaml +0 -63
  492. egse/stages/huber/smc9300_cs.py +0 -178
  493. egse/stages/huber/smc9300_devif.py +0 -345
  494. egse/stages/huber/smc9300_protocol.py +0 -113
  495. egse/stages/huber/smc9300_sim.py +0 -547
  496. egse/stages/huber/smc9300_ui.py +0 -973
  497. egse/state.py +0 -173
  498. egse/statemachine.py +0 -274
  499. egse/storage/__init__.py +0 -1067
  500. egse/storage/persistence.py +0 -2295
  501. egse/storage/storage.yaml +0 -79
  502. egse/storage/storage_cs.py +0 -231
  503. egse/styles/dark.qss +0 -343
  504. egse/styles/default.qss +0 -48
  505. egse/synoptics/__init__.py +0 -417
  506. egse/synoptics/syn.yaml +0 -9
  507. egse/synoptics/syn_cs.py +0 -195
  508. egse/system.py +0 -1611
  509. egse/tcs/__init__.py +0 -14
  510. egse/tcs/tcs.py +0 -879
  511. egse/tcs/tcs.yaml +0 -14
  512. egse/tcs/tcs_cs.py +0 -202
  513. egse/tcs/tcs_devif.py +0 -292
  514. egse/tcs/tcs_protocol.py +0 -180
  515. egse/tcs/tcs_sim.py +0 -177
  516. egse/tcs/tcs_ui.py +0 -543
  517. egse/tdms.py +0 -171
  518. egse/tempcontrol/__init__.py +0 -23
  519. egse/tempcontrol/agilent/agilent34970.py +0 -109
  520. egse/tempcontrol/agilent/agilent34970.yaml +0 -44
  521. egse/tempcontrol/agilent/agilent34970_cs.py +0 -114
  522. egse/tempcontrol/agilent/agilent34970_devif.py +0 -182
  523. egse/tempcontrol/agilent/agilent34970_protocol.py +0 -96
  524. egse/tempcontrol/agilent/agilent34972.py +0 -111
  525. egse/tempcontrol/agilent/agilent34972.yaml +0 -44
  526. egse/tempcontrol/agilent/agilent34972_cs.py +0 -115
  527. egse/tempcontrol/agilent/agilent34972_devif.py +0 -189
  528. egse/tempcontrol/agilent/agilent34972_protocol.py +0 -98
  529. egse/tempcontrol/beaglebone/beaglebone.py +0 -341
  530. egse/tempcontrol/beaglebone/beaglebone.yaml +0 -110
  531. egse/tempcontrol/beaglebone/beaglebone_cs.py +0 -117
  532. egse/tempcontrol/beaglebone/beaglebone_protocol.py +0 -134
  533. egse/tempcontrol/beaglebone/beaglebone_ui.py +0 -674
  534. egse/tempcontrol/digalox/digalox.py +0 -115
  535. egse/tempcontrol/digalox/digalox.yaml +0 -36
  536. egse/tempcontrol/digalox/digalox_cs.py +0 -108
  537. egse/tempcontrol/digalox/digalox_protocol.py +0 -56
  538. egse/tempcontrol/keithley/__init__.py +0 -33
  539. egse/tempcontrol/keithley/daq6510.py +0 -662
  540. egse/tempcontrol/keithley/daq6510.yaml +0 -105
  541. egse/tempcontrol/keithley/daq6510_cs.py +0 -163
  542. egse/tempcontrol/keithley/daq6510_devif.py +0 -343
  543. egse/tempcontrol/keithley/daq6510_protocol.py +0 -79
  544. egse/tempcontrol/keithley/daq6510_sim.py +0 -186
  545. egse/tempcontrol/lakeshore/__init__.py +0 -33
  546. egse/tempcontrol/lakeshore/lsci.py +0 -361
  547. egse/tempcontrol/lakeshore/lsci.yaml +0 -162
  548. egse/tempcontrol/lakeshore/lsci_cs.py +0 -174
  549. egse/tempcontrol/lakeshore/lsci_devif.py +0 -292
  550. egse/tempcontrol/lakeshore/lsci_protocol.py +0 -76
  551. egse/tempcontrol/lakeshore/lsci_ui.py +0 -387
  552. egse/tempcontrol/ni/__init__.py +0 -0
  553. egse/tempcontrol/spid/spid.py +0 -109
  554. egse/tempcontrol/spid/spid.yaml +0 -81
  555. egse/tempcontrol/spid/spid_controller.py +0 -279
  556. egse/tempcontrol/spid/spid_cs.py +0 -136
  557. egse/tempcontrol/spid/spid_protocol.py +0 -107
  558. egse/tempcontrol/spid/spid_ui.py +0 -723
  559. egse/tempcontrol/srs/__init__.py +0 -22
  560. egse/tempcontrol/srs/ptc10.py +0 -867
  561. egse/tempcontrol/srs/ptc10.yaml +0 -227
  562. egse/tempcontrol/srs/ptc10_cs.py +0 -128
  563. egse/tempcontrol/srs/ptc10_devif.py +0 -116
  564. egse/tempcontrol/srs/ptc10_protocol.py +0 -39
  565. egse/tempcontrol/srs/ptc10_ui.py +0 -906
  566. egse/ups/apc/apc.py +0 -236
  567. egse/ups/apc/apc.yaml +0 -45
  568. egse/ups/apc/apc_cs.py +0 -101
  569. egse/ups/apc/apc_protocol.py +0 -125
  570. egse/user.yaml +0 -7
  571. egse/vacuum/beaglebone/beaglebone.py +0 -149
  572. egse/vacuum/beaglebone/beaglebone.yaml +0 -44
  573. egse/vacuum/beaglebone/beaglebone_cs.py +0 -108
  574. egse/vacuum/beaglebone/beaglebone_devif.py +0 -159
  575. egse/vacuum/beaglebone/beaglebone_protocol.py +0 -192
  576. egse/vacuum/beaglebone/beaglebone_ui.py +0 -638
  577. egse/vacuum/instrutech/igm402.py +0 -91
  578. egse/vacuum/instrutech/igm402.yaml +0 -90
  579. egse/vacuum/instrutech/igm402_controller.py +0 -124
  580. egse/vacuum/instrutech/igm402_cs.py +0 -108
  581. egse/vacuum/instrutech/igm402_interface.py +0 -49
  582. egse/vacuum/instrutech/igm402_simulator.py +0 -36
  583. egse/vacuum/keller/kellerBus.py +0 -256
  584. egse/vacuum/keller/leo3.py +0 -100
  585. egse/vacuum/keller/leo3.yaml +0 -38
  586. egse/vacuum/keller/leo3_controller.py +0 -81
  587. egse/vacuum/keller/leo3_cs.py +0 -101
  588. egse/vacuum/keller/leo3_interface.py +0 -33
  589. egse/vacuum/mks/evision.py +0 -86
  590. egse/vacuum/mks/evision.yaml +0 -75
  591. egse/vacuum/mks/evision_cs.py +0 -101
  592. egse/vacuum/mks/evision_devif.py +0 -313
  593. egse/vacuum/mks/evision_interface.py +0 -60
  594. egse/vacuum/mks/evision_simulator.py +0 -24
  595. egse/vacuum/mks/evision_ui.py +0 -701
  596. egse/vacuum/pfeiffer/acp40.py +0 -87
  597. egse/vacuum/pfeiffer/acp40.yaml +0 -60
  598. egse/vacuum/pfeiffer/acp40_controller.py +0 -117
  599. egse/vacuum/pfeiffer/acp40_cs.py +0 -109
  600. egse/vacuum/pfeiffer/acp40_interface.py +0 -40
  601. egse/vacuum/pfeiffer/acp40_simulator.py +0 -37
  602. egse/vacuum/pfeiffer/tc400.py +0 -87
  603. egse/vacuum/pfeiffer/tc400.yaml +0 -83
  604. egse/vacuum/pfeiffer/tc400_controller.py +0 -136
  605. egse/vacuum/pfeiffer/tc400_cs.py +0 -109
  606. egse/vacuum/pfeiffer/tc400_interface.py +0 -70
  607. egse/vacuum/pfeiffer/tc400_simulator.py +0 -35
  608. egse/vacuum/pfeiffer/tpg261.py +0 -80
  609. egse/vacuum/pfeiffer/tpg261.yaml +0 -66
  610. egse/vacuum/pfeiffer/tpg261_controller.py +0 -150
  611. egse/vacuum/pfeiffer/tpg261_cs.py +0 -109
  612. egse/vacuum/pfeiffer/tpg261_interface.py +0 -59
  613. egse/vacuum/pfeiffer/tpg261_simulator.py +0 -23
  614. egse/version.py +0 -174
  615. egse/visitedpositions.py +0 -398
  616. egse/windowing.py +0 -213
  617. egse/zmq/__init__.py +0 -28
  618. egse/zmq/spw.py +0 -160
  619. egse/zmq_ser.py +0 -41
  620. scripts/alerts/cold.yaml +0 -278
  621. scripts/alerts/example_alerts.yaml +0 -54
  622. scripts/alerts/transition.yaml +0 -14
  623. scripts/alerts/warm.yaml +0 -49
  624. scripts/analyse_n_fee_hk_data.py +0 -52
  625. scripts/check_hdf5_files.py +0 -192
  626. scripts/check_register_sync.py +0 -47
  627. scripts/check_tcs_calib_coef.py +0 -90
  628. scripts/correct_ccd_cold_temperature_cal.py +0 -157
  629. scripts/create_hdf5_report.py +0 -293
  630. scripts/csl_model.py +0 -420
  631. scripts/csl_restore_setup.py +0 -229
  632. scripts/export-grafana-dashboards.py +0 -49
  633. scripts/fdir/cs_recovery/fdir_cs_recovery.py +0 -54
  634. scripts/fdir/fdir_table.yaml +0 -70
  635. scripts/fdir/fdir_test_recovery.py +0 -10
  636. scripts/fdir/hw_recovery/fdir_agilent_hw_recovery.py +0 -73
  637. scripts/fdir/limit_recovery/fdir_agilent_limit.py +0 -61
  638. scripts/fdir/limit_recovery/fdir_bb_heater_limit.py +0 -59
  639. scripts/fdir/limit_recovery/fdir_ensemble_limit.py +0 -33
  640. scripts/fdir/limit_recovery/fdir_pressure_limit_recovery.py +0 -71
  641. scripts/fix_csv.py +0 -80
  642. scripts/ias/correct_ccd_temp_cal_elfique.py +0 -43
  643. scripts/ias/correct_ccd_temp_cal_floreffe.py +0 -43
  644. scripts/ias/correct_trp_swap_achel.py +0 -199
  645. scripts/inta/correct_ccd_temp_cal_duvel.py +0 -43
  646. scripts/inta/correct_ccd_temp_cal_gueuze.py +0 -43
  647. scripts/n_fee_supply_voltage_calculation.py +0 -92
  648. scripts/playground.py +0 -30
  649. scripts/print_hdf5_hk_data.py +0 -68
  650. scripts/print_register_map.py +0 -43
  651. scripts/remove_lines_between_matches.py +0 -188
  652. scripts/sron/commanding/control_heaters.py +0 -44
  653. scripts/sron/commanding/pumpdown.py +0 -46
  654. scripts/sron/commanding/set_pid_setpoint.py +0 -19
  655. scripts/sron/commanding/shutdown_bbb_heaters.py +0 -10
  656. scripts/sron/commanding/shutdown_pumps.py +0 -33
  657. scripts/sron/correct_mgse_coordinates_brigand_chimay.py +0 -272
  658. scripts/sron/correct_trp_swap_brigand.py +0 -204
  659. scripts/sron/gimbal_conversions.py +0 -75
  660. scripts/sron/tm_gen/tm_gen_agilent.py +0 -37
  661. scripts/sron/tm_gen/tm_gen_heaters.py +0 -4
  662. scripts/sron/tm_gen/tm_gen_spid.py +0 -13
  663. scripts/update_operational_cgse.py +0 -268
  664. scripts/update_operational_cgse_old.py +0 -273
egse/setup.py DELETED
@@ -1,1181 +0,0 @@
1
- """
2
- This module defines the Setup, which contains the complete configuration information for a test.
3
-
4
- The Setup class contains all configuration items that are specific for a test or observation
5
- and is normally (during nominal operation/testing) loaded automatically from the configuration
6
- manager. The Setup includes type and identification of hardware that is used, calibration files,
7
- software versions, reference frames and coordinate systems that link positions of alignment
8
- equipment, conversion functions for temperature sensors, etc.
9
-
10
- The configuration information that is in the Setup can be navigated in two different ways. First,
11
- the Setup is a dictionary, so all information can be accessed by keys as in the following example.
12
-
13
- >>> setup = Setup({"gse": {"hexapod": {"ID": 42, "calibration": [0,1,2,3,4,5]}}})
14
- >>> setup["gse"]["hexapod"]["ID"]
15
- 42
16
-
17
- Second, each of the _keys_ is also available as an attribute of the Setup and that make it
18
- possible to navigate the Setup with dot-notation:
19
-
20
- >>> id = setup.gse.hexapod.ID
21
-
22
- In the above example you can see how to navigate from the setup to a device like the PUNA Hexapod.
23
- The Hexapod device is connected to the control server and accepts commands as usual. If you want to
24
- know which keys you can use to navigate the Setup, use the `keys()` method.
25
-
26
- >>> setup.gse.hexapod.keys()
27
- dict_keys(['ID', 'calibration'])
28
- >>> setup.gse.hexapod.calibration
29
- [0, 1, 2, 3, 4, 5]
30
-
31
- To get a full printout of the Setup, you can use the `pretty_str()` method. Be careful, because
32
- this can print out a lot of information when a full Setup is loaded.
33
-
34
- >>> print(setup)
35
- gse:
36
- hexapod:
37
- ID: 42
38
- calibration: [0, 1, 2, 3, 4, 5]
39
- <BLANKLINE>
40
-
41
- ### Special Values
42
-
43
- Some of the information in the Setup is interpreted in a special way, i.e. some values are
44
- processed before returning. Examples are the device classes and calibration/data files. The
45
- following values are treated special if they start with:
46
-
47
- * `class//`: the class in instantiated and the object is returned
48
- * `csv//`: the CSV file is loaded and a numpy array is returned
49
- * `yaml//`: the YAML file is loaded and a dictionary is returned
50
- * `enum//`: the enumeration is created dynamically and the object is returned
51
-
52
- #### Device Classes
53
-
54
- Most of the hardware components in the Setup will have a `device` key that defines the class for
55
- the device controller. The `device` keys have a value that starts with `class//` and it will
56
- return the device object. As an example, the following defines the Hexapod device:
57
-
58
- >>> setup = Setup({
59
- ... "gse": {
60
- ... "hexapod": {"ID": 42, "device": "class//egse.hexapod.symetrie.puna.PunaSimulator"}
61
- ... }
62
- ... })
63
- >>> setup.gse.hexapod.device.is_homing_done()
64
- False
65
- >>> setup.gse.hexapod.device.info() # doctest: +ELLIPSIS
66
- 'Info about the PunaSimulator...
67
-
68
- In the above example you see that we can call the `is_homing_done()` and `info()` methodes
69
- directly on the device by navigating the Setup. It would however be better (more performant) to
70
- put the device object in a variable and work with that variable:
71
-
72
- >>> hexapod = setup.gse.hexapod.device
73
- >>> _ = hexapod.homing()
74
- >>> hexapod.is_homing_done()
75
- True
76
- >>> _ = hexapod.get_user_positions()
77
-
78
- If you need, for some reason, to have access to the actual raw value of the hexapod device key,
79
- use the `get_raw_value()` method:
80
-
81
- >>> setup.gse.hexapod.get_raw_value("device") # doctest: +ELLIPSIS
82
- <egse.hexapod.symetrie.puna.PunaSimulator object at ...
83
-
84
- #### Data Files
85
-
86
- Some information is too large to add to the Setup as such and should be loaded from a data file.
87
- Examples are calibration files, flat-fields, temperature conversion curves, etc.
88
-
89
- The Setup will automatically load the file when you access a key that contains a value that
90
- starts with `csv//` or `yaml//`.
91
-
92
- >>> setup = Setup({
93
- ... "instrument": {"coeff": "csv//cal_coeff_1234.csv"}
94
- ... })
95
- >>> setup.instrument.coeff[0, 4]
96
- 5.0
97
-
98
- Note: the resource location is always relative to the path defined by the PLATO_CONF_DATA_LOCATION
99
- environment variable.
100
-
101
- """
102
- from __future__ import annotations
103
-
104
- import enum
105
- import importlib
106
- import logging
107
- import os
108
- import re
109
- import textwrap
110
- from functools import lru_cache
111
- from pathlib import Path
112
- from typing import Any
113
- from typing import Optional
114
- from typing import Union
115
-
116
- import rich
117
- import yaml
118
- from rich.tree import Tree
119
-
120
- from egse.control import Failure
121
- from egse.system import format_datetime
122
- from egse.system import sanity_check
123
- from egse.system import walk_dict_tree
124
-
125
- MODULE_LOGGER = logging.getLogger(__name__)
126
-
127
-
128
- class SetupError(Exception):
129
- """ A setup-specific error."""
130
- pass
131
-
132
-
133
- def _load_class(class_name: str):
134
- """Find and returns a class based on the fully qualified name.
135
-
136
- A class name can be preceded with the string `class//`. This is used in YAML
137
- files where the class is then instantiated on load.
138
-
139
- Args:
140
- class_name (str): a fully qualified name for the class
141
- """
142
- if class_name.startswith("class//"):
143
- class_name = class_name[7:]
144
- elif class_name.startswith("factory//"):
145
- class_name = class_name[9:]
146
-
147
- module_name, class_name = class_name.rsplit(".", 1)
148
- module = importlib.import_module(module_name)
149
- return getattr(module, class_name)
150
-
151
-
152
- def _load_csv(resource_name: str):
153
- """Find and return the content of a CSV file."""
154
- from numpy import genfromtxt
155
-
156
- parts = resource_name[5:].rsplit("/", 1)
157
- [in_dir, fn] = parts if len(parts) > 1 else [None, parts[0]]
158
- conf_location = os.environ['PLATO_CONF_DATA_LOCATION']
159
- try:
160
- csv_location = Path(conf_location) / in_dir / fn
161
- content = genfromtxt(csv_location, delimiter=",", skip_header=1)
162
- except TypeError as exc:
163
- raise ValueError(
164
- f"Couldn't load resource '{resource_name}' from default {conf_location=}") from exc
165
- return content
166
-
167
-
168
- def _load_int_enum(enum_name: str, enum_content):
169
- """ Dynamically build (and return) and IntEnum.
170
-
171
- Args:
172
- - enum_name: Enumeration name (potentially prepended with "int_enum//").
173
- - enum_content: Content of the enumeration, as read from the setup.
174
- """
175
- if enum_name.startswith("int_enum//"):
176
- enum_name = enum_name[10:]
177
-
178
- definition = {}
179
- for side_name, side_definition in enum_content.items():
180
-
181
- if "alias" in side_definition:
182
- aliases = side_definition["alias"]
183
- else:
184
- aliases = []
185
- value = side_definition["value"]
186
-
187
- definition[side_name] = value
188
-
189
- for alias in aliases:
190
- definition[alias] = value
191
- return enum.IntEnum(enum_name, definition)
192
-
193
-
194
- def _load_yaml(resource_name: str):
195
- """Find and return the content of a YAML file."""
196
- from egse.settings import Settings
197
- from egse.settings import SettingsError
198
-
199
- parts = resource_name[6:].rsplit("/", 1)
200
- [in_dir, fn] = parts if len(parts) > 1 else [None, parts[0]]
201
- conf_location = os.environ['PLATO_CONF_DATA_LOCATION']
202
- try:
203
- yaml_location = Path(conf_location) / in_dir / fn
204
- content = NavigableDict(Settings.load(filename=yaml_location, add_local_settings=False))
205
- except (TypeError, SettingsError) as exc:
206
- raise ValueError(
207
- f"Couldn't load resource '{resource_name}' from default {conf_location=}") from exc
208
- return content
209
-
210
-
211
- def _load_pandas(resource_name: str, separator: str):
212
- """ Find and return the content of the given files as a pandas DataFrame object.
213
-
214
- Args:
215
- - resource_name: Filename, preceded by "pandas//".
216
- - separator: Column separator.
217
- """
218
- import pandas
219
-
220
- parts = resource_name[8:].rsplit("/", 1)
221
- [in_dir, fn] = parts if len(parts) > 1 else [None, parts[0]]
222
- conf_location = os.environ['PLATO_CONF_DATA_LOCATION']
223
-
224
- try:
225
- pandas_file_location = Path(conf_location) / in_dir / fn
226
- return pandas.read_csv(pandas_file_location, sep=separator)
227
- except TypeError as exc:
228
- raise ValueError(
229
- f"Couldn't load resource '{resource_name}' from default {conf_location=}") from exc
230
-
231
-
232
- def _get_attribute(self, name, default):
233
- try:
234
- attr = object.__getattribute__(self, name)
235
- except AttributeError:
236
- attr = default
237
- return attr
238
-
239
-
240
- def _parse_filename_for_setup_id(filename: str):
241
- """Returns the setup_id from the filename, or None when no match was found."""
242
-
243
- match = re.search(r"SETUP_([^_]+)_(\d+)", filename)
244
-
245
- # TypeError when match is None
246
-
247
- try:
248
- return match[2] # match[2] is setup_id
249
- except (IndexError, TypeError) as exc:
250
- return None
251
-
252
-
253
- def get_last_setup_id_file_path(site_id: str = None) -> Path:
254
- """
255
- Return the fully expanded file path of the file containing the last loaded Setup in the configuration manager.
256
-
257
- Args:
258
- site_id: The SITE identifier
259
-
260
- """
261
- from egse.env import get_data_storage_location
262
- from egse.settings import Settings
263
-
264
- site_id = site_id or Settings.load("SITE").ID
265
- location = get_data_storage_location(site_id=site_id)
266
-
267
- return Path(location).expanduser().resolve() / "last_setup_id.txt"
268
-
269
-
270
- def load_last_setup_id(site_id: str = None) -> int:
271
- """
272
- Returns the ID of the last Setup that was used by the configuration manager.
273
- The file shall only contain the Setup ID which must be an integer on the first line of the file.
274
- If no such ID can be found, the Setup ID = 0 will be returned.
275
-
276
- Args:
277
- site_id: The SITE identifier
278
- """
279
-
280
- last_setup_id_file_path = get_last_setup_id_file_path(site_id=site_id)
281
- try:
282
- with last_setup_id_file_path.open('r') as fd:
283
- setup_id = int(fd.read().strip())
284
- except FileNotFoundError:
285
- setup_id = 0
286
- save_last_setup_id(setup_id)
287
-
288
- return setup_id
289
-
290
-
291
- def save_last_setup_id(setup_id: int | str, site_id: str = None):
292
- """
293
- Makes the given Setup ID persistent, so it can be restored upon the next startup.
294
-
295
- Args:
296
- setup_id: The Setup identifier to be saved
297
- site_id: The SITE identifier
298
-
299
- """
300
-
301
- last_setup_id_file_path = get_last_setup_id_file_path(site_id=site_id)
302
- with last_setup_id_file_path.open('w') as fd:
303
- fd.write(f"{int(setup_id):d}")
304
-
305
-
306
- class NavigableDict(dict):
307
- """
308
- A NavigableDict is a dictionary where all keys in the original dictionary are also accessible
309
- as attributes to the class instance. So, if the original dictionary (setup) has a key
310
- "site_id" which is accessible as `setup['site_id']`, it will also be accessible as
311
- `setup.site_id`.
312
-
313
- Examples:
314
- >>> setup = NavigableDict({'site_id': 'KU Leuven', 'version': "0.1.0"})
315
- >>> assert setup['site_id'] == setup.site_id
316
- >>> assert setup['version'] == setup.version
317
-
318
- .. note::
319
- We always want **all** keys to be accessible as attributes, or none. That means all
320
- keys of the original dictionary shall be of type `str`.
321
-
322
- """
323
-
324
- def __init__(self, head: dict = None):
325
- """
326
- Args:
327
- head (dict): the original dictionary
328
- """
329
- head = head or {}
330
- super().__init__(head)
331
- self.__dict__["_memoized"] = {}
332
-
333
- # By agreement, we only want the keys to be set as attributes if all keys are strings.
334
- # That way we enforce that always all keys are navigable, or none.
335
-
336
- if any(True for k in head.keys() if not isinstance(k, str)):
337
- return
338
-
339
- for key, value in head.items():
340
- if isinstance(value, dict):
341
- setattr(self, key, NavigableDict(head.__getitem__(key)))
342
- else:
343
- setattr(self, key, head.__getitem__(key))
344
-
345
- def add(self, key: str, value: Any):
346
- """Set a value for the given key.
347
-
348
- If the value is a dictionary, it will be converted into a NavigableDict and the keys
349
- will become available as attributes provided that all the keys are strings.
350
-
351
- Args:
352
- key (str): the name of the key / attribute to access the value
353
- value (Any): the value to assign to the key
354
- """
355
- if isinstance(value, dict) and not isinstance(value, NavigableDict):
356
- value = NavigableDict(value)
357
- setattr(self, key, value)
358
-
359
- def clear(self) -> None:
360
- for key in list(self.keys()):
361
- self.__delitem__(key)
362
-
363
- def __repr__(self):
364
- return f"{self.__class__.__name__}({super()!r})"
365
-
366
- def __delitem__(self, key):
367
- dict.__delitem__(self, key)
368
- object.__delattr__(self, key)
369
-
370
- def __setattr__(self, key, value):
371
- # MODULE_LOGGER.info(f"called __setattr__({self!r}, {key}, {value})")
372
- if isinstance(value, dict) and not isinstance(value, NavigableDict):
373
- value = NavigableDict(value)
374
- self.__dict__[key] = value
375
- super().__setitem__(key, value)
376
- try:
377
- del self.__dict__["_memoized"][key]
378
- except KeyError:
379
- pass
380
-
381
- def __getattribute__(self, key):
382
- # MODULE_LOGGER.info(f"called __getattribute__({key})")
383
- value = object.__getattribute__(self, key)
384
- if isinstance(value, str) and value.startswith("class//"):
385
- try:
386
- dev_args = object.__getattribute__(self, 'device_args')
387
- except AttributeError:
388
- dev_args = ()
389
- return _load_class(value)(*dev_args)
390
- if isinstance(value, str) and value.startswith("factory//"):
391
- factory_args = _get_attribute(self, f'{key}_args', {})
392
- return _load_class(value)().create(**factory_args)
393
- if isinstance(value, str) and value.startswith("int_enum//"):
394
- content = object.__getattribute__(self, "content")
395
- return _load_int_enum(value, content)
396
- if isinstance(value, str) and value.startswith("csv//"):
397
- if key in self.__dict__["_memoized"]:
398
- return self.__dict__["_memoized"][key]
399
- content = _load_csv(value)
400
- self.__dict__["_memoized"][key] = content
401
- return content
402
- if isinstance(value, str) and value.startswith("yaml//"):
403
- if key in self.__dict__["_memoized"]:
404
- return self.__dict__["_memoized"][key]
405
- content = _load_yaml(value)
406
- self.__dict__["_memoized"][key] = content
407
- return content
408
- if isinstance(value, str) and value.startswith("pandas//"):
409
- separator = object.__getattribute__(self, 'separator')
410
- return _load_pandas(value, separator)
411
- else:
412
- return value
413
-
414
- def __delattr__(self, item):
415
- # MODULE_LOGGER.info(f"called __delattr__({self!r}, {item})")
416
- object.__delattr__(self, item)
417
- dict.__delitem__(self, item)
418
-
419
- def __setitem__(self, key, value):
420
- # MODULE_LOGGER.info(f"called __setitem__({self!r}, {key}, {value})")
421
- if isinstance(value, dict) and not isinstance(value, NavigableDict):
422
- value = NavigableDict(value)
423
- super().__setitem__(key, value)
424
- self.__dict__[key] = value
425
- try:
426
- del self.__dict__["_memoized"][key]
427
- except KeyError:
428
- pass
429
-
430
- def __getitem__(self, key):
431
- # MODULE_LOGGER.info(f"called __getitem__({self!r}, {key})")
432
- value = super().__getitem__(key)
433
- if isinstance(value, str) and value.startswith("class//"):
434
- try:
435
- dev_args = object.__getattribute__(self, 'device_args')
436
- except AttributeError:
437
- dev_args = ()
438
- return _load_class(value)(*dev_args)
439
- if isinstance(value, str) and value.startswith("csv//"):
440
- return _load_csv(value)
441
- if isinstance(value, str) and value.startswith("int_enum//"):
442
- content = object.__getattribute__(self, "content")
443
- return _load_int_enum(value, content)
444
- else:
445
- return value
446
-
447
- def set_private_attribute(self, key: str, value) -> None:
448
- """Sets a private attribute for this object.
449
-
450
- The name in key will be accessible as an attribute for this object, but the key will not
451
- be added to the dictionary and not be returned by methods like keys().
452
-
453
- The idea behind this private attribute is to have the possibility to add status information
454
- or identifiers to this classes object that can be used by save() or load() methods.
455
-
456
- Args:
457
- key (str): the name of the private attribute (must start with an underscore character).
458
- value: the value for this private attribute
459
-
460
- Returns:
461
- None.
462
-
463
- Examples:
464
- >>> setup = NavigableDict({'a': 1, 'b': 2, 'c': 3})
465
- >>> setup.set_private_attribute("_loaded_from_dict", True)
466
- >>> assert "c" in setup
467
- >>> assert "_loaded_from_dict" not in setup
468
- >>> assert setup.get_private_attribute("_loaded_from_dict") == True
469
-
470
- """
471
- if key in self:
472
- raise ValueError(
473
- f"Invalid argument key='{key}', this key already exists in dictionary."
474
- )
475
- if not key.startswith("_"):
476
- raise ValueError(
477
- f"Invalid argument key='{key}', must start with underscore character '_'."
478
- )
479
- self.__dict__[key] = value
480
-
481
- def get_private_attribute(self, key: str):
482
- """Returns the value of the given private attribute.
483
-
484
- Args:
485
- key (str): the name of the private attribute (must start with an underscore character).
486
-
487
- Returns:
488
- the value of the private attribute given in `key`.
489
-
490
- .. note::
491
- Because of the implementation, this private attribute can also be accessed as a 'normal'
492
- attribute of the object. This use is however discouraged as it will make your code less
493
- understandable. Use the methods to access these 'private' attributes.
494
- """
495
- if not key.startswith("_"):
496
- raise ValueError(
497
- f"Invalid argument key='{key}', must start with underscore character '_'."
498
- )
499
- return self.__dict__[key]
500
-
501
- def has_private_attribute(self, key):
502
- """
503
- Check if the given key is defined as a private attribute.
504
-
505
- Args:
506
- key (str): the name of a private attribute (must start with an underscore)
507
- Returns:
508
- True if the given key is a known private attribute.
509
- Raises:
510
- ValueError: when the key doesn't start with an underscore.
511
- """
512
- if not key.startswith("_"):
513
- raise ValueError(
514
- f"Invalid argument key='{key}', must start with underscore character '_'."
515
- )
516
- try:
517
- self.__dict__[key]
518
- return True
519
- except KeyError:
520
- return False
521
-
522
- def get_raw_value(self, key):
523
- """
524
- Returns the raw value of the given key.
525
-
526
- Some keys have special values that are interpreted by the AtributeDict class. An example is
527
- a value that starts with 'class//'. When you access these values, they are first converted
528
- from their raw value into their expected value, e.g. the instantiated object in the above
529
- example. This method allows you to access the raw value before conversion.
530
- """
531
- try:
532
- return object.__getattribute__(self, key)
533
- except AttributeError:
534
- raise KeyError(f"The key '{key}' is not defined.")
535
-
536
- def __str__(self):
537
- return self.pretty_str()
538
-
539
- def pretty_str(self, indent: int = 0):
540
- """
541
- Returns a pretty string representation of the dictionary.
542
-
543
- Args:
544
- indent (int): number of indentations (of four spaces)
545
-
546
- .. note::
547
- The indent argument is intended for the recursive call of this function.
548
- """
549
- msg = ""
550
-
551
- for k, v in self.items():
552
- if isinstance(v, NavigableDict):
553
- msg += f"{' '*indent}{k}:\n"
554
- msg += v.pretty_str(indent + 1)
555
- else:
556
- msg += f"{' '*indent}{k}: {v}\n"
557
-
558
- return msg
559
-
560
- def __rich__(self) -> Tree:
561
- tree = Tree("NavigableDict", guide_style="dim")
562
- walk_dict_tree(self, tree, text_style="dark grey")
563
- return tree
564
-
565
- def _save(self, fd, indent: int = 0):
566
- """
567
- Recursive method to write the dictionary to the file descriptor.
568
-
569
- Indentation is done in steps of four spaces, i.e. `' '*indent`.
570
-
571
- Args:
572
- fd: a file descriptor as returned by the open() function
573
- indent (int): indentation level of each line [default = 0]
574
-
575
- """
576
- from egse.device import DeviceInterface
577
-
578
- # Note that the .items() method returns the actual values of the keys and doesn't use the
579
- # __getattribute__ or __getitem__ methods. So the raw value is returned and not the
580
- # _processed_ value.
581
-
582
- for k, v in self.items():
583
-
584
- # history shall be saved last, skip it for now
585
-
586
- if k == "history":
587
- continue
588
-
589
- # make sure to escape a colon in the key name
590
-
591
- if isinstance(k, str) and ":" in k:
592
- k = '"' + k + '"'
593
-
594
- if isinstance(v, NavigableDict):
595
- fd.write(f"{' '*indent}{k}:\n")
596
- v._save(fd, indent + 1)
597
- fd.flush()
598
- continue
599
-
600
- if isinstance(v, DeviceInterface):
601
- v = f"class//{v.__module__}.{v.__class__.__name__}"
602
- if isinstance(v, float):
603
- v = f"{v:.6E}"
604
- fd.write(f"{' '*indent}{k}: {v}\n")
605
- fd.flush()
606
-
607
- # now save the history as the last item
608
-
609
- if "history" in self:
610
- fd.write(f"{' ' * indent}history:\n")
611
- self.history._save(fd, indent + 1)
612
-
613
- def get_memoized_keys(self):
614
- return list(self.__dict__["_memoized"].keys())
615
-
616
-
617
- class Setup(NavigableDict):
618
- """The Setup class represents a version of the configuration of the test facility, the
619
- test setup and the Camera Under Test (CUT)."""
620
-
621
- def __init__(self, nav_dict: NavigableDict = None):
622
- super().__init__(nav_dict or {})
623
-
624
- @staticmethod
625
- def from_dict(my_dict):
626
- """Create a Setup from a given dictionary.
627
-
628
- Remember that all keys in the given dictionary shall be of type 'str' in order to be
629
- accessible as attributes.
630
-
631
- Examples:
632
- >>> setup = Setup.from_dict({"ID": "my-setup-001", "version": "0.1.0"})
633
- >>> assert setup["ID"] == setup.ID == "my-setup-001"
634
-
635
- """
636
- return Setup(my_dict)
637
-
638
- @staticmethod
639
- def from_yaml_string(yaml_content: str = None):
640
- """Loads a Setup from the given YAML string.
641
-
642
- This method is mainly used for easy creation of Setups from strings during unit tests.
643
-
644
- Args:
645
- yaml_content (str): a string containing YAML
646
-
647
- Returns:
648
- a Setup that was loaded from the content of the given string.
649
- """
650
-
651
- if not yaml_content:
652
- raise ValueError("Invalid argument to function: No input string or None given.")
653
-
654
- setup_dict = yaml.safe_load(yaml_content)
655
-
656
- if "Setup" in setup_dict:
657
- setup_dict = setup_dict["Setup"]
658
-
659
- return Setup(setup_dict)
660
-
661
- @staticmethod
662
- @lru_cache
663
- def from_yaml_file(filename: Union[str, Path] = None):
664
- """Loads a Setup from the given YAML file.
665
-
666
- Args:
667
- filename (str): the path of the YAML file to be loaded
668
-
669
- Returns:
670
- a Setup that was loaded from the given location.
671
- """
672
- from egse.settings import Settings
673
-
674
- if not filename:
675
- raise ValueError("Invalid argument to function: No filename or None given.")
676
-
677
- setup_dict = Settings.load("Setup", filename=filename, force=True)
678
-
679
- setup = Setup(setup_dict)
680
- setup.set_private_attribute("_filename", filename)
681
- if setup_id := _parse_filename_for_setup_id(str(filename)):
682
- setup.set_private_attribute("_setup_id", setup_id)
683
-
684
- return setup
685
-
686
- def to_yaml_file(self, filename=None):
687
- """Saves a NavigableDict to a YAML file.
688
-
689
- When no filename is provided, this method will look for a 'private' attribute
690
- `_filename` and use that to save the data.
691
-
692
- Args:
693
- filename (str): the path of the YAML file where to save the data
694
-
695
- .. note::
696
- This method will **overwrite** the original or given YAML file and therefore you might
697
- lose proper formatting and/or comments.
698
-
699
- """
700
- if not filename:
701
- try:
702
- filename = self.get_private_attribute("_filename")
703
- except KeyError:
704
- raise ValueError("No filename given or known, can not save Setup.")
705
-
706
- print(f"Saving Setup to {filename}")
707
-
708
- with Path(filename).open("w") as fd:
709
-
710
- fd.write(
711
- f"# Setup generated by:\n"
712
- f"#\n"
713
- f"# Setup.to_yaml_file(setup, filename='{filename}')\n#\n"
714
- )
715
- fd.write(f"# Created on {format_datetime()}\n\n")
716
- fd.write("Setup:\n")
717
-
718
- self._save(fd, indent=1)
719
-
720
- self.set_private_attribute("_filename", filename)
721
-
722
- @staticmethod
723
- def compare(setup_1: NavigableDict, setup_2: NavigableDict):
724
- from egse.device import DeviceInterface
725
- from egse.dpu import DPUSimulator
726
- from deepdiff import DeepDiff
727
-
728
- return DeepDiff(setup_1, setup_2, exclude_types={DeviceInterface, DPUSimulator})
729
-
730
- # def get_devices(self):
731
- # """Returns a list of devices for the current setup.
732
-
733
- # Returns:
734
- # - List of devices for the current setup.
735
- # """
736
-
737
- # devices = []
738
-
739
- # Setup.walk(self, "device", devices)
740
-
741
- # return devices
742
-
743
- @staticmethod
744
- def find_devices(node: NavigableDict, devices={}):
745
- """
746
- Returns a dictionary with the devices that are included in the setup. The keys
747
- in the dictionary are taken from the "device_name" entries in the setup file. The
748
- corresponding values in the dictionary are taken from the "device" entries in the
749
- setup file.
750
-
751
- Args:
752
- - node: Dictionary in which to look for the devices (and their names).
753
- - devices: Dictionary in which to include the devices in the setup.
754
-
755
- Returns:
756
- - Dictionary with the devices that are included in the setup.
757
- """
758
-
759
- for sub_node in node.values():
760
-
761
- if isinstance(sub_node, NavigableDict):
762
-
763
- if ("device" in sub_node) and ("device_name" in sub_node):
764
-
765
- device = sub_node.get_raw_value("device")
766
-
767
- if "device_args" in sub_node:
768
- device_args = sub_node.get_raw_value("device_args")
769
- else:
770
- device_args = ()
771
-
772
- devices[sub_node["device_name"]] = (device, device_args)
773
-
774
- else:
775
-
776
- Setup.find_devices(sub_node, devices=devices)
777
-
778
- return devices
779
-
780
- @staticmethod
781
- def walk(node: dict, key_of_interest, leaf_list):
782
-
783
- """
784
- Walk through the given dictionary, in a recursive way, appending the leaf with
785
- the given keyword to the given list.
786
-
787
- Args:
788
- - node: Dictionary in which to look for leaves with the given keyword.
789
- - key_of_interest: Key to look for in the leaves of the given dictionary.
790
- - leaf_list: List to which to add the leaves with the given keyword.
791
-
792
- Returns:
793
- - Given list with the leaves (with the given keyword) in the given dictionary
794
- appended to it.
795
- """
796
-
797
- for key, sub_node in node.items():
798
-
799
- if isinstance(sub_node, dict):
800
-
801
- Setup.walk(sub_node, key_of_interest, leaf_list)
802
-
803
- elif key == key_of_interest:
804
-
805
- leaf_list.append(sub_node)
806
-
807
- def __rich__(self) -> Tree:
808
- tree = super().__rich__()
809
- if self.has_private_attribute("_setup_id"):
810
- setup_id = self.get_private_attribute('_setup_id')
811
- tree.add(f"Setup ID: {setup_id}", style="grey50")
812
- if self.has_private_attribute("_filename"):
813
- filename = self.get_private_attribute('_filename')
814
- tree.add(f"Loaded from: {filename}", style="grey50")
815
- return tree
816
-
817
- def get_id(self) -> Optional[str]:
818
- """Returns the Setup ID (as a string) or None when no setup id could be identified."""
819
- if self.has_private_attribute("_setup_id"):
820
- return self.get_private_attribute('_setup_id')
821
- else:
822
- return None
823
-
824
- def get_filename(self) -> Optional[str]:
825
- """Returns the filename for this Setup or None when no filename could be determined."""
826
- if self.has_private_attribute("_filename"):
827
- return self.get_private_attribute('_filename')
828
- else:
829
- return None
830
-
831
-
832
- def list_setups(**attr):
833
- """
834
- This is a function to be used for interactive use, it will print to the terminal (stdout) a
835
- list of Setups known at the Configuration Manager. This list is sorted with the most recent (
836
- highest) value last.
837
-
838
- The list can be restricted with key:value pairs (keyword arguments). This _search_ mechanism
839
- allows us to find all Setups that adhere to the key:value pairs, e.g. to find all Setups for
840
- CSL at position 2, use:
841
-
842
- >>> list_setups(site_id="CSL", position=2)
843
-
844
- To have a nested keyword search (i.e. search by `gse.hexapod.ID`) then pass in
845
- `gse__hexapod__ID` as the keyword argument. Replace the '.' notation with double underscores
846
- '__'.
847
-
848
- >>> list_setups(gse__hexapod__ID=4)
849
- """
850
-
851
- from egse.confman import ConfigurationManagerProxy
852
-
853
- try:
854
- with ConfigurationManagerProxy() as proxy:
855
- setups = proxy.list_setups(**attr)
856
- if setups:
857
- # We want to have the most recent (highest id number) last, but keep the site together
858
- setups = sorted(setups, key=lambda x: (x[1], x[0]))
859
- print("\n".join(f"{setup}" for setup in setups))
860
- else:
861
- print("no Setups found")
862
- except ConnectionError:
863
- print("Could not make a connection with the Configuration Manager, no Setup to show you.")
864
-
865
-
866
- def get_setup(setup_id: int = None):
867
- """
868
- Retrieve the currently active Setup from the configuration manager.
869
-
870
- When a setup_id is provided, that setup will be returned, but not loaded in the configuration
871
- manager. This function does NOT change the configuration manager.
872
-
873
- This function is for interactive use and consults the configuration manager server. Don't use
874
- this within the test script, but use the `GlobalState.setup` property instead.
875
- """
876
- from egse.confman import ConfigurationManagerProxy
877
-
878
- try:
879
- with ConfigurationManagerProxy(timeout=1000) as proxy:
880
- setup = proxy.get_setup(setup_id)
881
- return setup
882
- except ConnectionError as exc:
883
- MODULE_LOGGER.warning(
884
- "Could not make a connection with the Configuration Manager, no Setup retrieved, None returned."
885
- )
886
- return None
887
-
888
-
889
- def _check_conditions_for_get_path_of_setup_file(site_id: str) -> Path:
890
- """
891
- Check some pre-conditions that need to be met before we try to determine the file path for
892
- the requested Setup file.
893
-
894
- The following checks are performed:
895
-
896
- * if the environment variable 'PLATO_CONF_REPO_LOCATION' is set
897
-
898
- * if the directory specified in the env variable actually exists
899
-
900
- * if the folder with the Setups exists for the given site_id
901
-
902
-
903
- Args:
904
- site_id (str): the name of the test house
905
-
906
- Returns:
907
- The location of the Setup files for the given test house.
908
-
909
- Raises:
910
- LookupError when the environment variable is not set.
911
-
912
- NotADirectoryError when either the repository folder or the Setups folder doesn't exist.
913
-
914
- """
915
- repo_location_env = 'PLATO_CONF_REPO_LOCATION'
916
- if not (repo_location := os.environ.get(repo_location_env)):
917
- raise LookupError(
918
- f"Environment variable doesn't exist, please define {repo_location_env} and try again."
919
- )
920
-
921
- repo_location = Path(repo_location)
922
- setup_location = repo_location / 'data' / site_id / 'conf'
923
-
924
- if not repo_location.is_dir():
925
- raise NotADirectoryError(
926
- f"The location of the repository for Setup files doesn't exist: {repo_location!s}. "
927
- f"Please check the environment variable {repo_location_env}."
928
- )
929
-
930
- if not setup_location.is_dir():
931
- raise NotADirectoryError(
932
- f"The location of the Setup files doesn't exist: {setup_location!s}. "
933
- f"Please check if the given {site_id=} is correct."
934
- )
935
-
936
- return setup_location
937
-
938
-
939
- def get_path_of_setup_file(setup_id: int, site_id: str) -> Path:
940
- """
941
- Returns the Path to the last Setup file for the given site_id. The last Setup file is the file
942
- with the largest setup_id number.
943
-
944
- This function needs the environment variable PLATO_CONF_REPO_LOCATION to be defined as the
945
- location of the repository 'plato-cgse-conf' on your disk.
946
-
947
- Args:
948
- setup_id (int): the identifier for the requested Setup
949
- site_id (str): the test house name, one of CSL, SRON, IAS, INTA
950
-
951
- Returns:
952
- The full path to the requested Setup file.
953
-
954
- Raises:
955
- LookupError when the environment variable is not set.
956
-
957
- NotADirectoryError when either the repository folder or the Setups folder doesn't exist.
958
-
959
- FileNotFound when no Setup file can be found for the given arguments.
960
-
961
- """
962
-
963
- setup_location = _check_conditions_for_get_path_of_setup_file(site_id)
964
-
965
- if setup_id:
966
- files = list(setup_location.glob(f'SETUP_{site_id}_{setup_id:05d}_*.yaml'))
967
-
968
- if not files:
969
- raise FileNotFoundError(f"No Setup found for {setup_id=} and {site_id=}.")
970
-
971
- file_path = Path(setup_location) / files[-1]
972
- else:
973
- files = setup_location.glob('SETUP*.yaml')
974
-
975
- last_file_parts = sorted([file.name.split('_') for file in files])[-1]
976
- file_path = Path(setup_location) / "_".join(last_file_parts)
977
-
978
- sanity_check(file_path.is_file(), f"The expected Setup file doesn't exist: {file_path!s}")
979
-
980
- return file_path
981
-
982
-
983
- def load_setup(
984
- setup_id: int = None,
985
- site_id: str = None, from_disk: bool = False):
986
- """
987
- This function loads the Setup corresponding with the given `setup_id`.
988
-
989
- Loading a Setup means:
990
-
991
- * that this Setup will also be loaded and activated in the configuration manager,
992
- * that this Setup will be available from the `GlobalState.setup`
993
-
994
- When no setup_id is provided, the current Setup is loaded from the configuration manager.
995
-
996
- Args:
997
- setup_id (int): the identifier for the Setup
998
- site_id (str): the name of the test house
999
- from_disk (bool): True if the Setup needs to be loaded from disk
1000
-
1001
- Returns:
1002
- The requested Setup or None when the Setup could not be loaded from the
1003
- configuration manager.
1004
-
1005
- """
1006
- from egse.state import GlobalState
1007
-
1008
- if from_disk:
1009
- if site_id is None:
1010
- raise ValueError(
1011
- "The site_id argument can not be empty when from_disk is given and True")
1012
-
1013
- setup_file_path = get_path_of_setup_file(setup_id, site_id)
1014
-
1015
- rich.print(
1016
- f"Loading {'' if setup_id else 'the latest '}Setup {f'{setup_id} ' if setup_id else ''}for {site_id}..."
1017
- )
1018
-
1019
- return Setup.from_yaml_file(setup_file_path)
1020
-
1021
- # When we arrive here the Setup shall be loaded from the Configuration manager
1022
-
1023
- from egse.confman import ConfigurationManagerProxy
1024
-
1025
- if setup_id is not None:
1026
- try:
1027
- with ConfigurationManagerProxy() as proxy:
1028
- proxy.load_setup(setup_id)
1029
-
1030
- except ConnectionError:
1031
- MODULE_LOGGER.warning(
1032
- "Could not make a connection with the Configuration Manager, no Setup to show you."
1033
- )
1034
- rich.print(
1035
- "\n"
1036
- "If you are not running this from an operational machine, do not have a CM "
1037
- "running locally or don't know what this means, then: \n"
1038
- " (1) define the environment variable 'PLATO_CONF_REPO_LOCATION' and \n"
1039
- " it points to the location of the plato-cgse-conf repository,\n"
1040
- " (2) try again using the argument 'from_disk=True'.\n"
1041
- )
1042
-
1043
- return GlobalState.load_setup()
1044
-
1045
-
1046
- def submit_setup(setup: Setup, description: str):
1047
- """
1048
- Submit the given Setup to the Configuration Manager.
1049
-
1050
- When you submit a Setup, the Configuration Manager will save this Setup with the
1051
- next (new) setup id and make this Setup the current Setup in the Configuration manager
1052
- unless you have explicitly set `replace=False` in which case the current Setup will
1053
- not be replaced with the new Setup.
1054
-
1055
- Args:
1056
- setup (Setup): a (new) Setup to submit to the configuration manager
1057
- description (str): one-liner to help identifying the Setup afterwards
1058
- Returns:
1059
- The Setup ID of the newly created Setup or None.
1060
- """
1061
- # We have not yet decided if this option should be made available. Therefore, we
1062
- # leave it here as hardcoded True.
1063
-
1064
- # replace (bool): True if the current Setup in the configuration manager shall
1065
- # be replaced by this new Setup. [default=True]
1066
- replace: bool = True
1067
-
1068
- from egse.confman import ConfigurationManagerProxy
1069
-
1070
- try:
1071
- with ConfigurationManagerProxy() as proxy:
1072
- setup = proxy.submit_setup(setup, description, replace)
1073
-
1074
- if setup is None:
1075
- rich.print("[red]Submit failed for given Setup, no reason given.[/red]")
1076
- elif isinstance(setup, Failure):
1077
- rich.print(f"[red]Submit failed for given Setup[/red]: {setup}")
1078
- setup = None
1079
- elif replace:
1080
- rich.print(textwrap.dedent(
1081
- f"""\
1082
- [green]
1083
- Your new setup has been submitted and pushed to GitHub. The new setup is also
1084
- activated in the configuration manager. Load the new setup in your session with:
1085
-
1086
- setup = load_setup()
1087
- [/]
1088
- """
1089
- ))
1090
- else:
1091
- rich.print(textwrap.dedent(
1092
- f"""\
1093
- [dark_orange]
1094
- Your new setup has been submitted and pushed to GitHub, but has not been
1095
- activated in the configuration manager. To activate this setup, use the
1096
- following command:
1097
-
1098
- setup = load_setup({str(setup.get_id())})
1099
- [/]
1100
- """)
1101
- )
1102
-
1103
- return setup.get_id() if setup is not None else None
1104
-
1105
- except ConnectionError:
1106
- rich.print("Could not make a connection with the Configuration Manager, no Setup was submitted.")
1107
- except NotImplementedError:
1108
- rich.print(textwrap.dedent(
1109
- """\
1110
- Caught a NotImplementedError. That usually means the configuration manager is not running or
1111
- can not be reached. Check on the egse-server if the `cm_cs` process is running. If not you will
1112
- need to be restart the core services.
1113
- """
1114
- ))
1115
-
1116
-
1117
- __all__ = [
1118
- "Setup",
1119
- "list_setups",
1120
- "load_setup",
1121
- "get_setup",
1122
- "submit_setup",
1123
- "SetupError",
1124
- "load_last_setup_id",
1125
- "save_last_setup_id",
1126
- ]
1127
-
1128
- if __name__ == "__main__":
1129
-
1130
- import sys
1131
- import argparse
1132
-
1133
- from rich import print
1134
-
1135
- from egse.config import find_files
1136
- from egse.settings import Settings
1137
-
1138
- SITE = Settings.load("SITE")
1139
- location = os.environ.get("PLATO_CONF_DATA_LOCATION")
1140
- parser = argparse.ArgumentParser(
1141
- description=textwrap.dedent(f"""\
1142
- Print out the Setup for the given setup-id. The Setup will
1143
- be loaded from the location given by the environment variable
1144
- PLATO_CONF_DATA_LOCATION. If this env is not set, the Setup
1145
- will be searched from the current directory."""
1146
- ),
1147
- epilog=f"PLATO_CONF_DATA_LOCATION={location}"
1148
- )
1149
- parser.add_argument(
1150
- "--setup-id", type=int, default=-1,
1151
- help="the Setup ID. If not given, the last Setup will be selected.")
1152
- parser.add_argument("--list", "-l", action="store_true", help="list available Setups.")
1153
- parser.add_argument("--use-cm", action="store_true", help="use the configuration manager.")
1154
- args = parser.parse_args()
1155
-
1156
- if args.use_cm:
1157
- from egse.confman import ConfigurationManagerProxy
1158
-
1159
- with ConfigurationManagerProxy() as cm:
1160
- if args.list:
1161
- print(cm.list_setups())
1162
- else:
1163
- print(cm.get_setup())
1164
- sys.exit(0)
1165
-
1166
- if args.list:
1167
- files = find_files(f"SETUP_{SITE.ID}_*_*.yaml", root=location)
1168
- files = list(files)
1169
- if files:
1170
- location = files[0].parent.resolve()
1171
- print(sorted([f.name for f in files]))
1172
- print(f"Loaded from [purple]{location}.")
1173
- else:
1174
- setup_id = args.setup_id
1175
- if setup_id == -1:
1176
- setup_files = find_files(f"SETUP_{SITE.ID}_*_*.yaml", root=location)
1177
- else:
1178
- setup_files = find_files(f"SETUP_{SITE.ID}_{setup_id:05d}_*.yaml", root=location)
1179
- setup_file = sorted(setup_files)[-1]
1180
- setup = Setup.from_yaml_file(setup_file)
1181
- print(setup)