setiastrosuitepro 1.6.7__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.

Potentially problematic release.


This version of setiastrosuitepro might be problematic. Click here for more details.

Files changed (394) hide show
  1. setiastro/__init__.py +2 -0
  2. setiastro/data/SASP_data.fits +0 -0
  3. setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
  4. setiastro/data/catalogs/astrobin_filters.csv +890 -0
  5. setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
  6. setiastro/data/catalogs/cali2.csv +63 -0
  7. setiastro/data/catalogs/cali2color.csv +65 -0
  8. setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
  9. setiastro/data/catalogs/celestial_catalog.csv +24031 -0
  10. setiastro/data/catalogs/detected_stars.csv +24784 -0
  11. setiastro/data/catalogs/fits_header_data.csv +46 -0
  12. setiastro/data/catalogs/test.csv +8 -0
  13. setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
  14. setiastro/images/Astro_Spikes.png +0 -0
  15. setiastro/images/Background_startup.jpg +0 -0
  16. setiastro/images/HRDiagram.png +0 -0
  17. setiastro/images/LExtract.png +0 -0
  18. setiastro/images/LInsert.png +0 -0
  19. setiastro/images/Oxygenation-atm-2.svg.png +0 -0
  20. setiastro/images/RGB080604.png +0 -0
  21. setiastro/images/abeicon.png +0 -0
  22. setiastro/images/aberration.png +0 -0
  23. setiastro/images/acv_icon.png +0 -0
  24. setiastro/images/andromedatry.png +0 -0
  25. setiastro/images/andromedatry_satellited.png +0 -0
  26. setiastro/images/annotated.png +0 -0
  27. setiastro/images/aperture.png +0 -0
  28. setiastro/images/astrosuite.ico +0 -0
  29. setiastro/images/astrosuite.png +0 -0
  30. setiastro/images/astrosuitepro.icns +0 -0
  31. setiastro/images/astrosuitepro.ico +0 -0
  32. setiastro/images/astrosuitepro.png +0 -0
  33. setiastro/images/background.png +0 -0
  34. setiastro/images/background2.png +0 -0
  35. setiastro/images/benchmark.png +0 -0
  36. setiastro/images/big_moon_stabilizer_timeline.png +0 -0
  37. setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
  38. setiastro/images/blaster.png +0 -0
  39. setiastro/images/blink.png +0 -0
  40. setiastro/images/clahe.png +0 -0
  41. setiastro/images/collage.png +0 -0
  42. setiastro/images/colorwheel.png +0 -0
  43. setiastro/images/contsub.png +0 -0
  44. setiastro/images/convo.png +0 -0
  45. setiastro/images/copyslot.png +0 -0
  46. setiastro/images/cosmic.png +0 -0
  47. setiastro/images/cosmicsat.png +0 -0
  48. setiastro/images/crop1.png +0 -0
  49. setiastro/images/cropicon.png +0 -0
  50. setiastro/images/curves.png +0 -0
  51. setiastro/images/cvs.png +0 -0
  52. setiastro/images/debayer.png +0 -0
  53. setiastro/images/denoise_cnn_custom.png +0 -0
  54. setiastro/images/denoise_cnn_graph.png +0 -0
  55. setiastro/images/disk.png +0 -0
  56. setiastro/images/dse.png +0 -0
  57. setiastro/images/exoicon.png +0 -0
  58. setiastro/images/eye.png +0 -0
  59. setiastro/images/first_quarter.png +0 -0
  60. setiastro/images/fliphorizontal.png +0 -0
  61. setiastro/images/flipvertical.png +0 -0
  62. setiastro/images/font.png +0 -0
  63. setiastro/images/freqsep.png +0 -0
  64. setiastro/images/full_moon.png +0 -0
  65. setiastro/images/functionbundle.png +0 -0
  66. setiastro/images/graxpert.png +0 -0
  67. setiastro/images/green.png +0 -0
  68. setiastro/images/gridicon.png +0 -0
  69. setiastro/images/halo.png +0 -0
  70. setiastro/images/hdr.png +0 -0
  71. setiastro/images/histogram.png +0 -0
  72. setiastro/images/hubble.png +0 -0
  73. setiastro/images/imagecombine.png +0 -0
  74. setiastro/images/invert.png +0 -0
  75. setiastro/images/isophote.png +0 -0
  76. setiastro/images/isophote_demo_figure.png +0 -0
  77. setiastro/images/isophote_demo_image.png +0 -0
  78. setiastro/images/isophote_demo_model.png +0 -0
  79. setiastro/images/isophote_demo_residual.png +0 -0
  80. setiastro/images/jwstpupil.png +0 -0
  81. setiastro/images/last_quarter.png +0 -0
  82. setiastro/images/linearfit.png +0 -0
  83. setiastro/images/livestacking.png +0 -0
  84. setiastro/images/mask.png +0 -0
  85. setiastro/images/maskapply.png +0 -0
  86. setiastro/images/maskcreate.png +0 -0
  87. setiastro/images/maskremove.png +0 -0
  88. setiastro/images/morpho.png +0 -0
  89. setiastro/images/mosaic.png +0 -0
  90. setiastro/images/multiscale_decomp.png +0 -0
  91. setiastro/images/nbtorgb.png +0 -0
  92. setiastro/images/neutral.png +0 -0
  93. setiastro/images/new_moon.png +0 -0
  94. setiastro/images/nuke.png +0 -0
  95. setiastro/images/openfile.png +0 -0
  96. setiastro/images/pedestal.png +0 -0
  97. setiastro/images/pen.png +0 -0
  98. setiastro/images/pixelmath.png +0 -0
  99. setiastro/images/platesolve.png +0 -0
  100. setiastro/images/ppp.png +0 -0
  101. setiastro/images/pro.png +0 -0
  102. setiastro/images/project.png +0 -0
  103. setiastro/images/psf.png +0 -0
  104. setiastro/images/redo.png +0 -0
  105. setiastro/images/redoicon.png +0 -0
  106. setiastro/images/rescale.png +0 -0
  107. setiastro/images/rgbalign.png +0 -0
  108. setiastro/images/rgbcombo.png +0 -0
  109. setiastro/images/rgbextract.png +0 -0
  110. setiastro/images/rotate180.png +0 -0
  111. setiastro/images/rotatearbitrary.png +0 -0
  112. setiastro/images/rotateclockwise.png +0 -0
  113. setiastro/images/rotatecounterclockwise.png +0 -0
  114. setiastro/images/satellite.png +0 -0
  115. setiastro/images/script.png +0 -0
  116. setiastro/images/selectivecolor.png +0 -0
  117. setiastro/images/simbad.png +0 -0
  118. setiastro/images/slot0.png +0 -0
  119. setiastro/images/slot1.png +0 -0
  120. setiastro/images/slot2.png +0 -0
  121. setiastro/images/slot3.png +0 -0
  122. setiastro/images/slot4.png +0 -0
  123. setiastro/images/slot5.png +0 -0
  124. setiastro/images/slot6.png +0 -0
  125. setiastro/images/slot7.png +0 -0
  126. setiastro/images/slot8.png +0 -0
  127. setiastro/images/slot9.png +0 -0
  128. setiastro/images/spcc.png +0 -0
  129. setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
  130. setiastro/images/spinner.gif +0 -0
  131. setiastro/images/stacking.png +0 -0
  132. setiastro/images/staradd.png +0 -0
  133. setiastro/images/staralign.png +0 -0
  134. setiastro/images/starnet.png +0 -0
  135. setiastro/images/starregistration.png +0 -0
  136. setiastro/images/starspike.png +0 -0
  137. setiastro/images/starstretch.png +0 -0
  138. setiastro/images/statstretch.png +0 -0
  139. setiastro/images/supernova.png +0 -0
  140. setiastro/images/uhs.png +0 -0
  141. setiastro/images/undoicon.png +0 -0
  142. setiastro/images/upscale.png +0 -0
  143. setiastro/images/viewbundle.png +0 -0
  144. setiastro/images/waning_crescent_1.png +0 -0
  145. setiastro/images/waning_crescent_2.png +0 -0
  146. setiastro/images/waning_crescent_3.png +0 -0
  147. setiastro/images/waning_crescent_4.png +0 -0
  148. setiastro/images/waning_crescent_5.png +0 -0
  149. setiastro/images/waning_gibbous_1.png +0 -0
  150. setiastro/images/waning_gibbous_2.png +0 -0
  151. setiastro/images/waning_gibbous_3.png +0 -0
  152. setiastro/images/waning_gibbous_4.png +0 -0
  153. setiastro/images/waning_gibbous_5.png +0 -0
  154. setiastro/images/waxing_crescent_1.png +0 -0
  155. setiastro/images/waxing_crescent_2.png +0 -0
  156. setiastro/images/waxing_crescent_3.png +0 -0
  157. setiastro/images/waxing_crescent_4.png +0 -0
  158. setiastro/images/waxing_crescent_5.png +0 -0
  159. setiastro/images/waxing_gibbous_1.png +0 -0
  160. setiastro/images/waxing_gibbous_2.png +0 -0
  161. setiastro/images/waxing_gibbous_3.png +0 -0
  162. setiastro/images/waxing_gibbous_4.png +0 -0
  163. setiastro/images/waxing_gibbous_5.png +0 -0
  164. setiastro/images/whitebalance.png +0 -0
  165. setiastro/images/wimi_icon_256x256.png +0 -0
  166. setiastro/images/wimilogo.png +0 -0
  167. setiastro/images/wims.png +0 -0
  168. setiastro/images/wrench_icon.png +0 -0
  169. setiastro/images/xisfliberator.png +0 -0
  170. setiastro/qml/ResourceMonitor.qml +128 -0
  171. setiastro/saspro/__init__.py +20 -0
  172. setiastro/saspro/__main__.py +964 -0
  173. setiastro/saspro/_generated/__init__.py +7 -0
  174. setiastro/saspro/_generated/build_info.py +3 -0
  175. setiastro/saspro/abe.py +1379 -0
  176. setiastro/saspro/abe_preset.py +196 -0
  177. setiastro/saspro/aberration_ai.py +910 -0
  178. setiastro/saspro/aberration_ai_preset.py +224 -0
  179. setiastro/saspro/accel_installer.py +218 -0
  180. setiastro/saspro/accel_workers.py +30 -0
  181. setiastro/saspro/acv_exporter.py +379 -0
  182. setiastro/saspro/add_stars.py +627 -0
  183. setiastro/saspro/astrobin_exporter.py +1010 -0
  184. setiastro/saspro/astrospike.py +153 -0
  185. setiastro/saspro/astrospike_python.py +1841 -0
  186. setiastro/saspro/autostretch.py +198 -0
  187. setiastro/saspro/backgroundneutral.py +639 -0
  188. setiastro/saspro/batch_convert.py +328 -0
  189. setiastro/saspro/batch_renamer.py +522 -0
  190. setiastro/saspro/blemish_blaster.py +494 -0
  191. setiastro/saspro/blink_comparator_pro.py +3149 -0
  192. setiastro/saspro/bundles.py +61 -0
  193. setiastro/saspro/bundles_dock.py +114 -0
  194. setiastro/saspro/cheat_sheet.py +213 -0
  195. setiastro/saspro/clahe.py +371 -0
  196. setiastro/saspro/comet_stacking.py +1442 -0
  197. setiastro/saspro/common_tr.py +107 -0
  198. setiastro/saspro/config.py +38 -0
  199. setiastro/saspro/config_bootstrap.py +40 -0
  200. setiastro/saspro/config_manager.py +316 -0
  201. setiastro/saspro/continuum_subtract.py +1620 -0
  202. setiastro/saspro/convo.py +1403 -0
  203. setiastro/saspro/convo_preset.py +414 -0
  204. setiastro/saspro/copyastro.py +190 -0
  205. setiastro/saspro/cosmicclarity.py +1593 -0
  206. setiastro/saspro/cosmicclarity_preset.py +407 -0
  207. setiastro/saspro/crop_dialog_pro.py +1005 -0
  208. setiastro/saspro/crop_preset.py +189 -0
  209. setiastro/saspro/curve_editor_pro.py +2608 -0
  210. setiastro/saspro/curves_preset.py +375 -0
  211. setiastro/saspro/debayer.py +673 -0
  212. setiastro/saspro/debug_utils.py +29 -0
  213. setiastro/saspro/dnd_mime.py +35 -0
  214. setiastro/saspro/doc_manager.py +2727 -0
  215. setiastro/saspro/exoplanet_detector.py +2258 -0
  216. setiastro/saspro/file_utils.py +284 -0
  217. setiastro/saspro/fitsmodifier.py +748 -0
  218. setiastro/saspro/fix_bom.py +32 -0
  219. setiastro/saspro/free_torch_memory.py +48 -0
  220. setiastro/saspro/frequency_separation.py +1352 -0
  221. setiastro/saspro/function_bundle.py +1596 -0
  222. setiastro/saspro/generate_translations.py +3092 -0
  223. setiastro/saspro/ghs_dialog_pro.py +728 -0
  224. setiastro/saspro/ghs_preset.py +284 -0
  225. setiastro/saspro/graxpert.py +638 -0
  226. setiastro/saspro/graxpert_preset.py +287 -0
  227. setiastro/saspro/gui/__init__.py +0 -0
  228. setiastro/saspro/gui/main_window.py +8928 -0
  229. setiastro/saspro/gui/mixins/__init__.py +33 -0
  230. setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
  231. setiastro/saspro/gui/mixins/file_mixin.py +450 -0
  232. setiastro/saspro/gui/mixins/geometry_mixin.py +503 -0
  233. setiastro/saspro/gui/mixins/header_mixin.py +441 -0
  234. setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
  235. setiastro/saspro/gui/mixins/menu_mixin.py +391 -0
  236. setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
  237. setiastro/saspro/gui/mixins/toolbar_mixin.py +1824 -0
  238. setiastro/saspro/gui/mixins/update_mixin.py +323 -0
  239. setiastro/saspro/gui/mixins/view_mixin.py +477 -0
  240. setiastro/saspro/gui/statistics_dialog.py +47 -0
  241. setiastro/saspro/halobgon.py +492 -0
  242. setiastro/saspro/header_viewer.py +448 -0
  243. setiastro/saspro/headless_utils.py +88 -0
  244. setiastro/saspro/histogram.py +760 -0
  245. setiastro/saspro/history_explorer.py +941 -0
  246. setiastro/saspro/i18n.py +168 -0
  247. setiastro/saspro/image_combine.py +421 -0
  248. setiastro/saspro/image_peeker_pro.py +1608 -0
  249. setiastro/saspro/imageops/__init__.py +37 -0
  250. setiastro/saspro/imageops/mdi_snap.py +292 -0
  251. setiastro/saspro/imageops/scnr.py +36 -0
  252. setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
  253. setiastro/saspro/imageops/stretch.py +236 -0
  254. setiastro/saspro/isophote.py +1186 -0
  255. setiastro/saspro/layers.py +208 -0
  256. setiastro/saspro/layers_dock.py +714 -0
  257. setiastro/saspro/lazy_imports.py +193 -0
  258. setiastro/saspro/legacy/__init__.py +2 -0
  259. setiastro/saspro/legacy/image_manager.py +2360 -0
  260. setiastro/saspro/legacy/numba_utils.py +3676 -0
  261. setiastro/saspro/legacy/xisf.py +1213 -0
  262. setiastro/saspro/linear_fit.py +537 -0
  263. setiastro/saspro/live_stacking.py +1854 -0
  264. setiastro/saspro/log_bus.py +5 -0
  265. setiastro/saspro/logging_config.py +460 -0
  266. setiastro/saspro/luminancerecombine.py +510 -0
  267. setiastro/saspro/main_helpers.py +201 -0
  268. setiastro/saspro/mask_creation.py +1090 -0
  269. setiastro/saspro/masks_core.py +56 -0
  270. setiastro/saspro/mdi_widgets.py +353 -0
  271. setiastro/saspro/memory_utils.py +666 -0
  272. setiastro/saspro/metadata_patcher.py +75 -0
  273. setiastro/saspro/mfdeconv.py +3909 -0
  274. setiastro/saspro/mfdeconv_earlystop.py +71 -0
  275. setiastro/saspro/mfdeconvcudnn.py +3312 -0
  276. setiastro/saspro/mfdeconvsport.py +2459 -0
  277. setiastro/saspro/minorbodycatalog.py +567 -0
  278. setiastro/saspro/morphology.py +411 -0
  279. setiastro/saspro/multiscale_decomp.py +1751 -0
  280. setiastro/saspro/nbtorgb_stars.py +541 -0
  281. setiastro/saspro/numba_utils.py +3145 -0
  282. setiastro/saspro/numba_warmup.py +141 -0
  283. setiastro/saspro/ops/__init__.py +9 -0
  284. setiastro/saspro/ops/command_help_dialog.py +623 -0
  285. setiastro/saspro/ops/command_runner.py +217 -0
  286. setiastro/saspro/ops/commands.py +1594 -0
  287. setiastro/saspro/ops/script_editor.py +1105 -0
  288. setiastro/saspro/ops/scripts.py +1476 -0
  289. setiastro/saspro/ops/settings.py +637 -0
  290. setiastro/saspro/parallel_utils.py +554 -0
  291. setiastro/saspro/pedestal.py +121 -0
  292. setiastro/saspro/perfect_palette_picker.py +1105 -0
  293. setiastro/saspro/pipeline.py +110 -0
  294. setiastro/saspro/pixelmath.py +1604 -0
  295. setiastro/saspro/plate_solver.py +2480 -0
  296. setiastro/saspro/project_io.py +797 -0
  297. setiastro/saspro/psf_utils.py +136 -0
  298. setiastro/saspro/psf_viewer.py +631 -0
  299. setiastro/saspro/pyi_rthook_astroquery.py +95 -0
  300. setiastro/saspro/remove_green.py +331 -0
  301. setiastro/saspro/remove_stars.py +1599 -0
  302. setiastro/saspro/remove_stars_preset.py +446 -0
  303. setiastro/saspro/resources.py +570 -0
  304. setiastro/saspro/rgb_combination.py +208 -0
  305. setiastro/saspro/rgb_extract.py +19 -0
  306. setiastro/saspro/rgbalign.py +727 -0
  307. setiastro/saspro/runtime_imports.py +7 -0
  308. setiastro/saspro/runtime_torch.py +754 -0
  309. setiastro/saspro/save_options.py +73 -0
  310. setiastro/saspro/selective_color.py +1614 -0
  311. setiastro/saspro/sfcc.py +1530 -0
  312. setiastro/saspro/shortcuts.py +3125 -0
  313. setiastro/saspro/signature_insert.py +1106 -0
  314. setiastro/saspro/stacking_suite.py +19069 -0
  315. setiastro/saspro/star_alignment.py +7383 -0
  316. setiastro/saspro/star_alignment_preset.py +329 -0
  317. setiastro/saspro/star_metrics.py +49 -0
  318. setiastro/saspro/star_spikes.py +769 -0
  319. setiastro/saspro/star_stretch.py +542 -0
  320. setiastro/saspro/stat_stretch.py +554 -0
  321. setiastro/saspro/status_log_dock.py +78 -0
  322. setiastro/saspro/subwindow.py +3523 -0
  323. setiastro/saspro/supernovaasteroidhunter.py +1719 -0
  324. setiastro/saspro/swap_manager.py +134 -0
  325. setiastro/saspro/torch_backend.py +89 -0
  326. setiastro/saspro/torch_rejection.py +434 -0
  327. setiastro/saspro/translations/all_source_strings.json +4726 -0
  328. setiastro/saspro/translations/ar_translations.py +4096 -0
  329. setiastro/saspro/translations/de_translations.py +3728 -0
  330. setiastro/saspro/translations/es_translations.py +4169 -0
  331. setiastro/saspro/translations/fr_translations.py +4090 -0
  332. setiastro/saspro/translations/hi_translations.py +3803 -0
  333. setiastro/saspro/translations/integrate_translations.py +271 -0
  334. setiastro/saspro/translations/it_translations.py +4728 -0
  335. setiastro/saspro/translations/ja_translations.py +3834 -0
  336. setiastro/saspro/translations/pt_translations.py +3847 -0
  337. setiastro/saspro/translations/ru_translations.py +3082 -0
  338. setiastro/saspro/translations/saspro_ar.qm +0 -0
  339. setiastro/saspro/translations/saspro_ar.ts +16019 -0
  340. setiastro/saspro/translations/saspro_de.qm +0 -0
  341. setiastro/saspro/translations/saspro_de.ts +14548 -0
  342. setiastro/saspro/translations/saspro_es.qm +0 -0
  343. setiastro/saspro/translations/saspro_es.ts +16202 -0
  344. setiastro/saspro/translations/saspro_fr.qm +0 -0
  345. setiastro/saspro/translations/saspro_fr.ts +15870 -0
  346. setiastro/saspro/translations/saspro_hi.qm +0 -0
  347. setiastro/saspro/translations/saspro_hi.ts +14855 -0
  348. setiastro/saspro/translations/saspro_it.qm +0 -0
  349. setiastro/saspro/translations/saspro_it.ts +19046 -0
  350. setiastro/saspro/translations/saspro_ja.qm +0 -0
  351. setiastro/saspro/translations/saspro_ja.ts +14980 -0
  352. setiastro/saspro/translations/saspro_pt.qm +0 -0
  353. setiastro/saspro/translations/saspro_pt.ts +15024 -0
  354. setiastro/saspro/translations/saspro_ru.qm +0 -0
  355. setiastro/saspro/translations/saspro_ru.ts +11835 -0
  356. setiastro/saspro/translations/saspro_sw.qm +0 -0
  357. setiastro/saspro/translations/saspro_sw.ts +15237 -0
  358. setiastro/saspro/translations/saspro_uk.qm +0 -0
  359. setiastro/saspro/translations/saspro_uk.ts +15248 -0
  360. setiastro/saspro/translations/saspro_zh.qm +0 -0
  361. setiastro/saspro/translations/saspro_zh.ts +15289 -0
  362. setiastro/saspro/translations/sw_translations.py +3897 -0
  363. setiastro/saspro/translations/uk_translations.py +3929 -0
  364. setiastro/saspro/translations/zh_translations.py +3910 -0
  365. setiastro/saspro/versioning.py +77 -0
  366. setiastro/saspro/view_bundle.py +1558 -0
  367. setiastro/saspro/wavescale_hdr.py +648 -0
  368. setiastro/saspro/wavescale_hdr_preset.py +101 -0
  369. setiastro/saspro/wavescalede.py +683 -0
  370. setiastro/saspro/wavescalede_preset.py +230 -0
  371. setiastro/saspro/wcs_update.py +374 -0
  372. setiastro/saspro/whitebalance.py +540 -0
  373. setiastro/saspro/widgets/__init__.py +48 -0
  374. setiastro/saspro/widgets/common_utilities.py +306 -0
  375. setiastro/saspro/widgets/graphics_views.py +122 -0
  376. setiastro/saspro/widgets/image_utils.py +518 -0
  377. setiastro/saspro/widgets/minigame/game.js +991 -0
  378. setiastro/saspro/widgets/minigame/index.html +53 -0
  379. setiastro/saspro/widgets/minigame/style.css +241 -0
  380. setiastro/saspro/widgets/preview_dialogs.py +280 -0
  381. setiastro/saspro/widgets/resource_monitor.py +313 -0
  382. setiastro/saspro/widgets/spinboxes.py +290 -0
  383. setiastro/saspro/widgets/themed_buttons.py +13 -0
  384. setiastro/saspro/widgets/wavelet_utils.py +331 -0
  385. setiastro/saspro/wimi.py +7367 -0
  386. setiastro/saspro/wims.py +588 -0
  387. setiastro/saspro/window_shelf.py +185 -0
  388. setiastro/saspro/xisf.py +1213 -0
  389. setiastrosuitepro-1.6.7.dist-info/METADATA +279 -0
  390. setiastrosuitepro-1.6.7.dist-info/RECORD +394 -0
  391. setiastrosuitepro-1.6.7.dist-info/WHEEL +4 -0
  392. setiastrosuitepro-1.6.7.dist-info/entry_points.txt +6 -0
  393. setiastrosuitepro-1.6.7.dist-info/licenses/LICENSE +674 -0
  394. setiastrosuitepro-1.6.7.dist-info/licenses/license.txt +2580 -0
@@ -0,0 +1,450 @@
1
+ # pro/gui/mixins/file_mixin.py
2
+ """
3
+ File operations mixin for AstroSuiteProMainWindow.
4
+ """
5
+ from __future__ import annotations
6
+ import os
7
+ from typing import TYPE_CHECKING
8
+
9
+ from PyQt6.QtCore import Qt
10
+ from PyQt6.QtWidgets import QFileDialog, QMessageBox, QProgressDialog
11
+
12
+ if TYPE_CHECKING:
13
+ pass
14
+
15
+
16
+ class FileMixin:
17
+ """
18
+ Mixin for file operations.
19
+
20
+ Provides methods for opening, saving, importing, and exporting files.
21
+ """
22
+
23
+ def _load_recent_lists(self):
24
+ """Load recent files and projects from settings."""
25
+ if not hasattr(self, "settings"):
26
+ return
27
+
28
+ self._recent_image_paths = self.settings.value("recent/images", [], type=list) or []
29
+ self._recent_project_paths = self.settings.value("recent/projects", [], type=list) or []
30
+
31
+ def _save_recent_lists(self):
32
+ """Save recent files and projects to settings."""
33
+ if not hasattr(self, "settings"):
34
+ return
35
+
36
+ self.settings.setValue("recent/images", self._recent_image_paths[:self._recent_max])
37
+ self.settings.setValue("recent/projects", self._recent_project_paths[:self._recent_max])
38
+
39
+ def _open_recent_image(self, path: str):
40
+ """
41
+ Open a recent image file.
42
+
43
+ Args:
44
+ path: Path to the image file
45
+ """
46
+ if hasattr(self, "open_files"):
47
+ self.open_files([path])
48
+
49
+ def _open_recent_project(self, path: str):
50
+ """
51
+ Open a recent project file.
52
+
53
+ Args:
54
+ path: Path to the project file
55
+ """
56
+ if hasattr(self, "load_project"):
57
+ self.load_project(path)
58
+
59
+ def _add_to_recent_images(self, path: str):
60
+ """
61
+ Add a path to recent images list.
62
+
63
+ Args:
64
+ path: Path to add
65
+ """
66
+ if path in self._recent_image_paths:
67
+ self._recent_image_paths.remove(path)
68
+ self._recent_image_paths.insert(0, path)
69
+ self._recent_image_paths = self._recent_image_paths[:self._recent_max]
70
+ self._save_recent_lists()
71
+ if hasattr(self, "_rebuild_recent_menus"):
72
+ self._rebuild_recent_menus()
73
+
74
+ def _add_to_recent_projects(self, path: str):
75
+ """
76
+ Add a path to recent projects list.
77
+
78
+ Args:
79
+ path: Path to add
80
+ """
81
+ if path in self._recent_project_paths:
82
+ self._recent_project_paths.remove(path)
83
+ self._recent_project_paths.insert(0, path)
84
+ self._recent_project_paths = self._recent_project_paths[:self._recent_max]
85
+ self._save_recent_lists()
86
+ if hasattr(self, "_rebuild_recent_menus"):
87
+ self._rebuild_recent_menus()
88
+ # Extracted FILE methods
89
+
90
+ def open_files(self):
91
+ # One-stop "All Supported" plus focused groups the user can switch to
92
+ filters = (
93
+ "All Supported (*.png *.jpg *.jpeg *.tif *.tiff "
94
+ "*.fits *.fit *.fits.gz *.fit.gz *.fz *.xisf "
95
+ "*.cr2 *.cr3 *.nef *.arw *.dng *.raf *.orf *.rw2 *.pef);;"
96
+ "Astro (FITS/XISF) (*.xisf *.fits *.fit *.fits.gz *.fit.gz *.fz);;"
97
+ "RAW Images (*.cr2 *.cr3 *.nef *.arw *.dng *.raf *.orf *.rw2 *.pef);;"
98
+ "Common Images (*.png *.jpg *.jpeg *.tif *.tiff);;"
99
+ "All Files (*)"
100
+ )
101
+
102
+ # read last dir; validate it still exists
103
+ last_dir = self.settings.value("paths/last_open_dir", "", type=str) or ""
104
+ if last_dir and not os.path.isdir(last_dir):
105
+ last_dir = ""
106
+
107
+ paths, _ = QFileDialog.getOpenFileNames(self, self.tr("Open Images"), last_dir, filters)
108
+ if not paths:
109
+ return
110
+
111
+ # store the directory of the first picked file
112
+ try:
113
+ self.settings.setValue("paths/last_open_dir", os.path.dirname(paths[0]))
114
+ except Exception:
115
+ pass
116
+
117
+ # open each path (doc_manager should emit documentAdded; no manual spawn)
118
+ for p in paths:
119
+ try:
120
+ doc = self.docman.open_path(p) # this emits documentAdded
121
+ self._log(f"Opened: {p}")
122
+ self._add_recent_image(p) # âœ... track in MRU
123
+
124
+ # Increment statistics
125
+ try:
126
+ count = self.settings.value("stats/opened_images_count", 0, type=int)
127
+ self.settings.setValue("stats/opened_images_count", count + 1)
128
+ except Exception:
129
+ pass
130
+ except Exception as e:
131
+ QMessageBox.warning(self, self.tr("Open failed"), f"{p}\n\n{e}")
132
+
133
+ def save_active(self):
134
+ from setiastro.saspro.main_helpers import (
135
+ best_doc_name as _best_doc_name,
136
+ normalize_save_path_chosen_filter as _normalize_save_path_chosen_filter,
137
+ )
138
+ from setiastro.saspro.file_utils import _sanitize_filename
139
+
140
+ doc = self._active_doc()
141
+ if not doc:
142
+ return
143
+
144
+ filters = (
145
+ "FITS (*.fits *.fit);;"
146
+ "XISF (*.xisf);;"
147
+ "TIFF (*.tif *.tiff);;"
148
+ "PNG (*.png);;"
149
+ "JPEG (*.jpg *.jpeg)"
150
+ )
151
+
152
+ # --- Determine initial directory nicely -----------------------------
153
+ # 1) Try the document's original file path (strip any "::HDU" or "::XISF[...]" suffix)
154
+ orig_path = (doc.metadata or {}).get("file_path", "") or ""
155
+ if "::" in orig_path:
156
+ # e.g. "/foo/bar/file.fits::HDU 2" or "...::XISF[3]"
157
+ orig_path_fs = orig_path.split("::", 1)[0]
158
+ else:
159
+ orig_path_fs = orig_path
160
+
161
+ candidate_dir = ""
162
+ try:
163
+ if orig_path_fs:
164
+ pdir = os.path.dirname(orig_path_fs)
165
+ if pdir and os.path.isdir(pdir):
166
+ candidate_dir = pdir
167
+ except Exception:
168
+ candidate_dir = ""
169
+
170
+ # 2) Else, fall back to last save dir setting
171
+ if not candidate_dir:
172
+ candidate_dir = self.settings.value("paths/last_save_dir", "", type=str) or ""
173
+
174
+ # 3) Else, home directory
175
+ if not candidate_dir or not os.path.isdir(candidate_dir):
176
+ from pathlib import Path
177
+ candidate_dir = str(Path.home())
178
+
179
+ # --- Suggest a sane filename ---------------------------------------
180
+ suggested = _best_doc_name(doc)
181
+ suggested = os.path.splitext(suggested)[0] # remove any ext
182
+ suggested_safe = _sanitize_filename(suggested)
183
+ suggested_path = os.path.join(candidate_dir, suggested_safe)
184
+
185
+ # --- Open dialog ----------------------------------------
186
+ path, selected_filter = QFileDialog.getSaveFileName(self, self.tr("Save As"), suggested_path, filters)
187
+ if not path:
188
+ return
189
+
190
+ before = path
191
+ path, ext_norm = _normalize_save_path_chosen_filter(path, selected_filter)
192
+
193
+ # If we changed the path (e.g., sanitized), inform once
194
+ if before != path:
195
+ self._log(f"Adjusted filename for safety:\n {before}\n-> {path}")
196
+
197
+ # --- Bit depth selection ----------------------------------------
198
+ from setiastro.saspro.save_options import SaveOptionsDialog
199
+ current_bd = doc.metadata.get("bit_depth")
200
+ dlg = SaveOptionsDialog(self, ext_norm, current_bd)
201
+ if dlg.exec() != dlg.DialogCode.Accepted:
202
+ return
203
+ chosen_bd = dlg.selected_bit_depth()
204
+
205
+ # --- Save & remember folder ----------------------------------------
206
+ try:
207
+ self.docman.save_document(doc, path, bit_depth_override=chosen_bd)
208
+ self._log(f"Saved: {path} ({chosen_bd})")
209
+ self.settings.setValue("paths/last_save_dir", os.path.dirname(path))
210
+ except Exception as e:
211
+ QMessageBox.critical(self, self.tr("Save failed"), str(e))
212
+
213
+ def _load_recent_lists(self):
214
+ """Load MRU lists from QSettings."""
215
+ def _as_list(val):
216
+ if val is None:
217
+ return []
218
+ if isinstance(val, list):
219
+ return [str(v) for v in val if v]
220
+ if isinstance(val, str):
221
+ if not val:
222
+ return []
223
+ # allow ";;" separated fallback if ever needed
224
+ return [s for s in val.split(";;") if s]
225
+ return []
226
+
227
+ self._recent_image_paths = _as_list(
228
+ self.settings.value("recent/image_paths", [])
229
+ )
230
+ self._recent_project_paths = _as_list(
231
+ self.settings.value("recent/project_paths", [])
232
+ )
233
+
234
+ # Enforce max + uniqueness (most recent first)
235
+ def _dedupe_keep_order(seq):
236
+ seen = set()
237
+ out = []
238
+ for p in seq:
239
+ if p in seen:
240
+ continue
241
+ seen.add(p)
242
+ out.append(p)
243
+ return out[: self._recent_max]
244
+
245
+ self._recent_image_paths = _dedupe_keep_order(self._recent_image_paths)
246
+ self._recent_project_paths = _dedupe_keep_order(self._recent_project_paths)
247
+
248
+ def _save_recent_lists(self):
249
+ try:
250
+ self.settings.setValue("recent/image_paths", self._recent_image_paths)
251
+ self.settings.setValue("recent/project_paths", self._recent_project_paths)
252
+ except Exception:
253
+ pass
254
+
255
+ def _open_recent_image(self, path: str):
256
+ if not path:
257
+ return
258
+ if not os.path.exists(path):
259
+ if QMessageBox.question(
260
+ self,
261
+ self.tr("File not found"),
262
+ self.tr("The file does not exist:\n{path}\n\nRemove it from the recent images list?").replace("{path}", path),
263
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
264
+ ) == QMessageBox.StandardButton.Yes:
265
+ self._recent_image_paths = [p for p in self._recent_image_paths if p != path]
266
+ self._save_recent_lists()
267
+ self._rebuild_recent_menus()
268
+ return
269
+
270
+ try:
271
+ self.docman.open_path(path)
272
+ self._log(f"Opened (recent): {path}")
273
+ # bump to front
274
+ self._add_recent_image(path)
275
+ except Exception as e:
276
+ QMessageBox.warning(self, self.tr("Open failed"), f"{path}\n\n{e}")
277
+
278
+ def _open_recent_project(self, path: str):
279
+ if not path:
280
+ return
281
+ if not os.path.exists(path):
282
+ if QMessageBox.question(
283
+ self,
284
+ self.tr("Project not found"),
285
+ self.tr("The project file does not exist:\n{path}\n\nRemove it from the recent projects list?").replace("{path}", path),
286
+ QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No,
287
+ ) == QMessageBox.StandardButton.Yes:
288
+ self._recent_project_paths = [p for p in self._recent_project_paths if p != path]
289
+ self._save_recent_lists()
290
+ self._rebuild_recent_menus()
291
+ return
292
+
293
+ if not self._prepare_for_project_load("Load Project"):
294
+ return
295
+
296
+ self._do_load_project_path(path)
297
+
298
+ def _add_recent_image(self, path: str):
299
+ p = os.path.abspath(path)
300
+ self._recent_image_paths = [p] + [
301
+ x for x in self._recent_image_paths if x != p
302
+ ]
303
+ self._recent_image_paths = self._recent_image_paths[: self._recent_max]
304
+ self._save_recent_lists()
305
+ self._rebuild_recent_menus()
306
+
307
+ def _add_recent_project(self, path: str):
308
+ p = os.path.abspath(path)
309
+ self._recent_project_paths = [p] + [
310
+ x for x in self._recent_project_paths if x != p
311
+ ]
312
+ self._recent_project_paths = self._recent_project_paths[: self._recent_max]
313
+ self._save_recent_lists()
314
+ self._rebuild_recent_menus()
315
+
316
+ def _save_project(self):
317
+ path, _ = QFileDialog.getSaveFileName(
318
+ self, self.tr("Save Project"), "", "SetiAstro Project (*.sas)"
319
+ )
320
+ if not path:
321
+ return
322
+ if not path.lower().endswith(".sas"):
323
+ path += ".sas"
324
+
325
+ docs = self._collect_open_documents()
326
+ if not docs:
327
+ QMessageBox.warning(self, self.tr("Save Project"), self.tr("No documents to save."))
328
+ return
329
+
330
+ try:
331
+ compress = self._ask_project_compress() # your existing yes/no dialog
332
+
333
+ # Busy dialog (indeterminate)
334
+ dlg = QProgressDialog(self.tr("Saving project..."), "", 0, 0, self)
335
+ dlg.setWindowTitle(self.tr("Saving"))
336
+ # PyQt6 (with PyQt5 fallback if you ever run it there)
337
+ try:
338
+ dlg.setWindowModality(Qt.WindowModality.ApplicationModal)
339
+ except AttributeError:
340
+ dlg.setWindowModality(Qt.ApplicationModal) # PyQt5
341
+
342
+ # Hide the cancel button (API differs across versions)
343
+ try:
344
+ dlg.setCancelButton(None)
345
+ except TypeError:
346
+ dlg.setCancelButtonText("")
347
+
348
+ dlg.setAutoClose(False)
349
+ dlg.setAutoReset(False)
350
+ dlg.show()
351
+
352
+ # Threaded save
353
+ from setiastro.saspro.widgets.common_utilities import ProjectSaveWorker as _ProjectSaveWorker
354
+
355
+ self._proj_save_worker = _ProjectSaveWorker(
356
+ path,
357
+ docs,
358
+ getattr(self, "shortcuts", None),
359
+ getattr(self, "mdi", None),
360
+ compress,
361
+ parent=self,
362
+ )
363
+
364
+ def _on_proj_save_ok():
365
+ dlg.close()
366
+ self._log("Project saved.")
367
+ self._add_recent_project(path)
368
+
369
+ self._proj_save_worker.ok.connect(_on_proj_save_ok)
370
+ self._proj_save_worker.error.connect(
371
+ lambda msg: (
372
+ dlg.close(),
373
+ QMessageBox.critical(self, self.tr("Save Project"), self.tr("Failed to save:\n{msg}").replace("{msg}", msg)),
374
+ )
375
+ )
376
+ self._proj_save_worker.finished.connect(
377
+ lambda: setattr(self, "_proj_save_worker", None)
378
+ )
379
+ self._proj_save_worker.start()
380
+
381
+ except Exception as e:
382
+ QMessageBox.critical(self, self.tr("Save Project"), self.tr("Failed to save:\n{e}").replace("{e}", str(e)))
383
+
384
+ def _load_project(self):
385
+ # warn / clear current desktop
386
+ if not self._prepare_for_project_load("Load Project"):
387
+ return
388
+
389
+ path, _ = QFileDialog.getOpenFileName(
390
+ self, self.tr("Load Project"), "", "SetiAstro Project (*.sas)"
391
+ )
392
+ if not path:
393
+ return
394
+
395
+ self._do_load_project_path(path)
396
+
397
+ def _new_project(self):
398
+ if not self._confirm_discard(title=self.tr("New Project"),
399
+ msg=self.tr("Start a new project? This closes all views and clears desktop shortcuts.")):
400
+ return
401
+
402
+ # Close views + docs + shelf
403
+ self._close_all_subwindows()
404
+ self._clear_all_documents()
405
+ self._clear_minimized_shelf()
406
+
407
+ # Clear desktop shortcuts (widgets + persisted positions)
408
+ try:
409
+ if getattr(self, "shortcuts", None):
410
+ self.shortcuts.clear()
411
+ else:
412
+ # Fallback: wipe persisted layout so nothing reloads later
413
+ from PyQt6.QtCore import QSettings
414
+ from setiastro.saspro.shortcuts import SET_KEY_V1, SET_KEY_V2
415
+ s = QSettings()
416
+ s.setValue(SET_KEY_V2, "[]")
417
+ s.remove(SET_KEY_V1)
418
+ s.sync()
419
+ except Exception:
420
+ pass
421
+
422
+ # (Optional) keep canvas ready for fresh adds
423
+ try:
424
+ if getattr(self, "shortcuts", None):
425
+ self.shortcuts.canvas.raise_()
426
+ self.shortcuts.canvas.show()
427
+ self.shortcuts.canvas.setFocus()
428
+ except Exception:
429
+ pass
430
+
431
+ self._log("New project workspace ready.")
432
+
433
+ def _collect_open_documents(self):
434
+ # Prefer DocManager if present
435
+ dm = getattr(self, "doc_manager", None) or getattr(self, "docman", None)
436
+ if dm is not None and getattr(dm, "_docs", None) is not None:
437
+ return list(dm._docs)
438
+
439
+ # Fallback: harvest from open subwindows
440
+ docs = []
441
+ for sw in self.mdi.subWindowList():
442
+ try:
443
+ view = sw.widget()
444
+ doc = getattr(view, "document", None)
445
+ if doc is not None:
446
+ docs.append(doc)
447
+ except Exception:
448
+ pass
449
+ return docs
450
+