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,964 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ Seti Astro Suite Pro - Main Entry Point Module
4
+
5
+ This module contains the main application entry point logic.
6
+ It can be executed directly via `python -m setiastro.saspro` or
7
+ called via the `main()` function when invoked as an entry point.
8
+ """
9
+
10
+ # Show splash screen IMMEDIATELY before any heavy imports
11
+
12
+ import sys
13
+ import os
14
+
15
+ from pathlib import Path
16
+
17
+ if sys.platform.startswith("win"):
18
+ exe_dir = Path(sys.executable).resolve().parent
19
+ internal = exe_dir / "_internal"
20
+ if internal.is_dir():
21
+ try:
22
+ os.add_dll_directory(str(internal))
23
+ except Exception:
24
+ pass
25
+ os.environ["PATH"] = str(internal) + os.pathsep + os.environ.get("PATH", "")
26
+
27
+ from PyQt6.QtCore import QCoreApplication
28
+
29
+ # ---- Linux Qt stability guard (must run BEFORE any PyQt6 import) ----
30
+ # Default behavior: DO NOT override Wayland.
31
+ # If a user needs the "safe" path, they can opt-in by setting:
32
+ # SASPRO_QT_SAFE=1
33
+ #
34
+ # This avoids punishing all Wayland users for one bad driver/Qt stack.
35
+ if sys.platform.startswith("linux"):
36
+ if os.environ.get("SASPRO_QT_SAFE", "").strip() in ("1", "true", "yes", "on"):
37
+ # Prefer X11/xcb unless user explicitly set a platform plugin
38
+ os.environ.setdefault("QT_QPA_PLATFORM", "xcb")
39
+
40
+ # Prefer software GL unless user explicitly set something else
41
+ os.environ.setdefault("QT_OPENGL", "software")
42
+ os.environ.setdefault("LIBGL_ALWAYS_SOFTWARE", "1")
43
+
44
+ # Global variables for splash screen and app
45
+ _splash = None
46
+ _app = None
47
+
48
+ # Flag to track if splash was initialized
49
+ _splash_initialized = False
50
+
51
+ from setiastro.saspro.versioning import get_app_version
52
+ _EARLY_VERSION = get_app_version("setiastrosuitepro")
53
+
54
+ VERSION = _EARLY_VERSION
55
+
56
+ def _init_splash():
57
+ """Initialize the splash screen. Safe to call multiple times."""
58
+ global _splash, _app, _splash_initialized
59
+
60
+ if _splash_initialized:
61
+ return
62
+
63
+ # Minimal imports for splash screen
64
+ from PyQt6.QtWidgets import QApplication, QWidget
65
+ from PyQt6.QtCore import Qt, QCoreApplication, QRect, QPropertyAnimation, QEasingCurve
66
+ import time
67
+ from PyQt6.QtGui import QGuiApplication, QIcon, QPixmap, QColor, QPainter, QFont, QLinearGradient
68
+
69
+
70
+ # If we're forcing software OpenGL, do it *before* QApplication is created.
71
+ if sys.platform.startswith("linux"):
72
+ if os.environ.get("SASPRO_QT_SAFE", "").strip() in ("1", "true", "yes", "on"):
73
+ if os.environ.get("QT_OPENGL", "").lower() == "software":
74
+ try:
75
+ QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_UseSoftwareOpenGL, True)
76
+ except Exception:
77
+ pass
78
+
79
+ # Set application attributes before creating QApplication
80
+ try:
81
+ QGuiApplication.setHighDpiScaleFactorRoundingPolicy(
82
+ Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
83
+ )
84
+ except Exception:
85
+ pass
86
+
87
+ QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_DontShowIconsInMenus, False)
88
+ QCoreApplication.setOrganizationName("SetiAstro")
89
+ QCoreApplication.setOrganizationDomain("setiastrosuite.pro")
90
+ QCoreApplication.setApplicationName("Seti Astro Suite Pro")
91
+
92
+ # Create QApplication
93
+ _app = QApplication(sys.argv)
94
+
95
+ try:
96
+ _app.setQuitOnLastWindowClosed(True)
97
+ except Exception:
98
+ pass
99
+
100
+ if sys.platform.startswith("linux"):
101
+ try:
102
+ print("Qt platform:", _app.platformName())
103
+ print("QuitOnLastWindowClosed:", _app.quitOnLastWindowClosed())
104
+ print("XDG_SESSION_TYPE:", os.environ.get("XDG_SESSION_TYPE"))
105
+ print("QT_QPA_PLATFORM:", os.environ.get("QT_QPA_PLATFORM"))
106
+ print("QT_OPENGL:", os.environ.get("QT_OPENGL"))
107
+ except Exception:
108
+ pass
109
+
110
+ # Determine icon paths early
111
+ # Determine icon paths early
112
+ def _find_icon_path():
113
+ """Legacy fallback if resources import fails."""
114
+ if hasattr(sys, '_MEIPASS'):
115
+ base = sys._MEIPASS
116
+ else:
117
+ try:
118
+ import setiastro
119
+ package_dir = os.path.dirname(os.path.abspath(setiastro.__file__))
120
+ package_parent = os.path.dirname(package_dir)
121
+ images_dir_installed = os.path.join(package_parent, 'images')
122
+ if os.path.exists(images_dir_installed):
123
+ base = package_parent
124
+ else:
125
+ base = os.path.dirname(
126
+ os.path.dirname(
127
+ os.path.dirname(
128
+ os.path.dirname(os.path.abspath(__file__))
129
+ )
130
+ )
131
+ )
132
+ except (ImportError, AttributeError):
133
+ base = os.path.dirname(
134
+ os.path.dirname(
135
+ os.path.dirname(
136
+ os.path.dirname(os.path.abspath(__file__))
137
+ )
138
+ )
139
+ )
140
+
141
+ candidates = [
142
+ os.path.join(base, "images", "astrosuitepro.png"),
143
+ os.path.join(base, "images", "astrosuitepro.ico"),
144
+ os.path.join(base, "images", "astrosuite.png"),
145
+ os.path.join(base, "images", "astrosuite.ico"),
146
+ ]
147
+ for p in candidates:
148
+ if os.path.exists(p):
149
+ return p
150
+ return "" # nothing found
151
+
152
+ # NEW: Prefer centralized resources resolver
153
+ try:
154
+ from setiastro.saspro.resources import icon_path, background_startup_path
155
+ _early_icon_path = icon_path
156
+ if not os.path.exists(_early_icon_path):
157
+ # fall back to legacy search if for some reason this is missing
158
+ _early_icon_path = _find_icon_path()
159
+
160
+ # Load startup background path
161
+ _startup_bg_path = background_startup_path
162
+ if not os.path.exists(_startup_bg_path):
163
+ _startup_bg_path = None
164
+
165
+ except Exception:
166
+ _early_icon_path = _find_icon_path()
167
+ _startup_bg_path = None
168
+
169
+
170
+ # =========================================================================
171
+ # PhotoshopStyleSplash - Custom splash screen widget
172
+ # =========================================================================
173
+ class _EarlySplash(QWidget):
174
+ """
175
+ A modern, Photoshop-style splash screen shown immediately on startup.
176
+ """
177
+ def __init__(self, logo_path: str):
178
+ super().__init__()
179
+ self._version = _EARLY_VERSION
180
+ self._build = ""
181
+ self.current_message = QCoreApplication.translate("Splash", "Starting...")
182
+ self.progress_value = 0
183
+
184
+ # Window setup
185
+ self.setWindowFlags(
186
+ Qt.WindowType.SplashScreen |
187
+ Qt.WindowType.FramelessWindowHint |
188
+ Qt.WindowType.WindowStaysOnTopHint
189
+ )
190
+ self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, False)
191
+ self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose, True)
192
+
193
+ # Splash dimensions
194
+ self.splash_width = 600
195
+ self.splash_height = 400
196
+ self.setFixedSize(self.splash_width, self.splash_height)
197
+
198
+ # Center on screen
199
+ screen = QGuiApplication.primaryScreen()
200
+ if screen:
201
+ screen_geo = screen.availableGeometry()
202
+ x = (screen_geo.width() - self.splash_width) // 2 + screen_geo.x()
203
+ y = (screen_geo.height() - self.splash_height) // 2 + screen_geo.y()
204
+ self.move(x, y)
205
+
206
+ # Load and scale logo
207
+ self.logo_pixmap = self._load_logo(logo_path)
208
+
209
+ # Load background image
210
+ self.bg_image_pixmap = QPixmap()
211
+ if _startup_bg_path:
212
+ self.bg_image_pixmap = QPixmap(_startup_bg_path)
213
+
214
+ # Fonts
215
+ self.title_font = QFont("Segoe UI", 28, QFont.Weight.Bold)
216
+ self.subtitle_font = QFont("Segoe UI", 11)
217
+ self.message_font = QFont("Segoe UI", 9)
218
+ self.copyright_font = QFont("Segoe UI", 8)
219
+
220
+ def _load_logo(self, path: str) -> QPixmap:
221
+ """Load the logo and scale appropriately."""
222
+ if not path or not os.path.exists(path):
223
+ return QPixmap()
224
+
225
+ ext = os.path.splitext(path)[1].lower()
226
+ if ext == ".ico":
227
+ ic = QIcon(path)
228
+ pm = ic.pixmap(256, 256)
229
+ if pm.isNull():
230
+ pm = QPixmap(path)
231
+ else:
232
+ pm = QPixmap(path)
233
+ if pm.isNull():
234
+ pm = QIcon(path).pixmap(256, 256)
235
+
236
+ if not pm.isNull():
237
+ pm = pm.scaled(
238
+ 180, 180,
239
+ Qt.AspectRatioMode.KeepAspectRatio,
240
+ Qt.TransformationMode.SmoothTransformation
241
+ )
242
+ return pm
243
+
244
+ def setMessage(self, message: str):
245
+ """Update the loading message."""
246
+ self.current_message = message
247
+ self.repaint()
248
+ if _app:
249
+ _app.processEvents()
250
+
251
+ def setProgress(self, value: int):
252
+ """Update progress (0-100) with smooth animation."""
253
+ target = max(0, min(100, value))
254
+ start = self.progress_value
255
+
256
+ # If jumping backwards or small change, just set it
257
+ if target <= start or (target - start) < 1:
258
+ self.progress_value = target
259
+ self.repaint()
260
+ if _app: _app.processEvents()
261
+ return
262
+
263
+ # Animate forward
264
+ steps = 15 # number of frames for the slide
265
+ # We want the total slide to take ~100-150ms max to feel responsive but smooth
266
+ dt = 0.005 # 5ms per frame
267
+
268
+ for i in range(1, steps + 1):
269
+ # Ease out interpolator
270
+ t = i / steps
271
+ # Quadratic ease out: f(t) = -t*(t-2)
272
+ factor = -t * (t - 2)
273
+
274
+ cur = start + (target - start) * factor
275
+ self.progress_value = cur
276
+ self.repaint()
277
+ if _app: _app.processEvents()
278
+ time.sleep(dt)
279
+
280
+ self.progress_value = target
281
+ self.repaint()
282
+ if _app:
283
+ _app.processEvents()
284
+
285
+ def setBuildInfo(self, version: str, build: str):
286
+ """Update version and build info once available."""
287
+ self._version = _EARLY_VERSION
288
+ self._build = build
289
+ self.repaint()
290
+
291
+ def paintEvent(self, event):
292
+ """Custom paint for the splash screen."""
293
+ painter = QPainter(self)
294
+ painter.setRenderHint(QPainter.RenderHint.Antialiasing)
295
+ painter.setRenderHint(QPainter.RenderHint.TextAntialiasing)
296
+
297
+ w, h = self.splash_width, self.splash_height
298
+
299
+ # --- Background gradient (deep space theme) ---
300
+ gradient = QLinearGradient(0, 0, 0, h)
301
+ gradient.setColorAt(0.0, QColor(15, 15, 25))
302
+ gradient.setColorAt(0.5, QColor(25, 25, 45))
303
+ gradient.setColorAt(1.0, QColor(10, 10, 20))
304
+ painter.fillRect(0, 0, w, h, gradient)
305
+
306
+ # --- Background Image (Centered with Fade Out) ---
307
+ if not self.bg_image_pixmap.isNull():
308
+ # Create a temporary pixmap to handle the masking
309
+ temp = QPixmap(w, h)
310
+ temp.fill(Qt.GlobalColor.transparent)
311
+
312
+ ptmp = QPainter(temp)
313
+ ptmp.setRenderHint(QPainter.RenderHint.Antialiasing)
314
+ ptmp.setRenderHint(QPainter.RenderHint.SmoothPixmapTransform)
315
+
316
+ # Scale image to cover the entire splash screen
317
+ scaled = self.bg_image_pixmap.scaled(
318
+ w, h,
319
+ Qt.AspectRatioMode.KeepAspectRatioByExpanding,
320
+ Qt.TransformationMode.SmoothTransformation
321
+ )
322
+
323
+ # Center the image
324
+ sx = (w - scaled.width()) // 2
325
+ sy = (h - scaled.height()) // 2
326
+ ptmp.drawPixmap(sx, sy, scaled)
327
+
328
+ # Apply Fade Out Mask (Gradient Alpha)
329
+ ptmp.setCompositionMode(QPainter.CompositionMode.CompositionMode_DestinationIn)
330
+ fade_gradient = QLinearGradient(0, 0, 0, h)
331
+ # Keep top half fully visible (subject to global opacity)
332
+ fade_gradient.setColorAt(0.0, QColor(0, 0, 0, 255))
333
+ fade_gradient.setColorAt(0.5, QColor(0, 0, 0, 255))
334
+ # Fade out completely at the bottom
335
+ fade_gradient.setColorAt(1.0, QColor(0, 0, 0, 0))
336
+ ptmp.fillRect(0, 0, w, h, fade_gradient)
337
+ ptmp.end()
338
+
339
+ # Draw combined result with 50% opacity
340
+ painter.save()
341
+ painter.setOpacity(0.25)
342
+ painter.drawPixmap(0, 0, temp)
343
+ painter.restore()
344
+
345
+ # --- Subtle border ---
346
+ painter.setPen(QColor(60, 60, 80))
347
+ painter.drawRect(0, 0, w - 1, h - 1)
348
+
349
+ # --- Logo (centered upper area) ---
350
+ if not self.logo_pixmap.isNull():
351
+ logo_x = (w - self.logo_pixmap.width()) // 2
352
+ logo_y = 40
353
+ painter.drawPixmap(logo_x, logo_y, self.logo_pixmap)
354
+
355
+ # --- Title ---
356
+ painter.setFont(self.title_font)
357
+ painter.setPen(QColor(255, 255, 255))
358
+ title_rect = QRect(0, 230, w, 40)
359
+ painter.drawText(title_rect, Qt.AlignmentFlag.AlignCenter, "Seti Astro Suite Pro")
360
+
361
+ # --- Subtitle with version ---
362
+ painter.setFont(self.subtitle_font)
363
+ painter.setPen(QColor(180, 180, 200))
364
+ subtitle_text = QCoreApplication.translate("Splash", "Version {0}").format(self._version)
365
+
366
+ if self._build:
367
+ if self._build == "dev":
368
+ # No build_info → running from source checkout
369
+ subtitle_text += QCoreApplication.translate("Splash", " • Running locally from source code")
370
+ else:
371
+ subtitle_text += QCoreApplication.translate("Splash", " • Build {0}").format(self._build)
372
+
373
+ subtitle_rect = QRect(0, 270, w, 25)
374
+ painter.drawText(subtitle_rect, Qt.AlignmentFlag.AlignCenter, subtitle_text)
375
+
376
+ # --- Progress bar ---
377
+ bar_margin = 50
378
+ bar_height = 4
379
+ bar_y = h - 70
380
+ bar_width = w - (bar_margin * 2)
381
+
382
+ painter.setPen(Qt.PenStyle.NoPen)
383
+ painter.setBrush(QColor(40, 40, 60))
384
+ painter.drawRoundedRect(bar_margin, bar_y, bar_width, bar_height, 2, 2)
385
+
386
+ if self.progress_value > 0:
387
+ fill_width = int(bar_width * self.progress_value / 100)
388
+ bar_gradient = QLinearGradient(bar_margin, 0, bar_margin + bar_width, 0)
389
+ bar_gradient.setColorAt(0.0, QColor(80, 140, 220))
390
+ bar_gradient.setColorAt(1.0, QColor(140, 180, 255))
391
+ painter.setBrush(bar_gradient)
392
+ painter.drawRoundedRect(bar_margin, bar_y, fill_width, bar_height, 2, 2)
393
+
394
+ # --- Loading message ---
395
+ painter.setFont(self.message_font)
396
+ painter.setPen(QColor(150, 150, 180))
397
+ msg_rect = QRect(bar_margin, bar_y + 10, bar_width, 20)
398
+ painter.drawText(msg_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter,
399
+ self.current_message)
400
+
401
+ # --- Copyright ---
402
+ painter.setFont(self.copyright_font)
403
+ painter.setPen(QColor(100, 100, 130))
404
+ copyright_text = "© 2024-2025 Franklin Marek (Seti Astro) • All Rights Reserved"
405
+ copyright_rect = QRect(0, h - 30, w, 20)
406
+ painter.drawText(copyright_rect, Qt.AlignmentFlag.AlignCenter, copyright_text)
407
+
408
+ painter.end()
409
+
410
+ def finish(self):
411
+ """Hide and cleanup the splash."""
412
+ self.hide()
413
+ self.close()
414
+ self.deleteLater()
415
+
416
+ def start_fade_out(self):
417
+ """Smoothly fade out the splash screen."""
418
+ self._anim = QPropertyAnimation(self, b"windowOpacity")
419
+ self._anim.setDuration(1000)
420
+ self._anim.setStartValue(1.0)
421
+ self._anim.setEndValue(0.0)
422
+ self._anim.setEasingCurve(QEasingCurve.Type.OutQuad)
423
+ self._anim.finished.connect(self.finish)
424
+ self._anim.start()
425
+
426
+ def start_fade_in(self):
427
+ """Smoothly fade in the splash screen."""
428
+ self.setWindowOpacity(0.0)
429
+ self._anim = QPropertyAnimation(self, b"windowOpacity")
430
+ self._anim.setDuration(800)
431
+ self._anim.setStartValue(0.0)
432
+ self._anim.setEndValue(1.0)
433
+ self._anim.setEasingCurve(QEasingCurve.Type.InQuad)
434
+ self._anim.start()
435
+
436
+ # --- Show splash IMMEDIATELY ---
437
+ _splash = _EarlySplash(_early_icon_path)
438
+ _splash.start_fade_in()
439
+ _splash.show()
440
+
441
+ # Block briefly to allow fade-in to progress smoothly before heavy imports start
442
+ # We use a busy loop with processEvents to keep the UI responsive during fade
443
+ t_start = time.time()
444
+ while time.time() - t_start < 0.85: # slightly longer than animation
445
+ _app.processEvents()
446
+ if _splash.windowOpacity() >= 0.99:
447
+ break
448
+ time.sleep(0.01)
449
+
450
+ _splash.setMessage(QCoreApplication.translate("Splash", "Initializing Python runtime..."))
451
+ _splash.setProgress(2)
452
+ _app.processEvents()
453
+
454
+ # Load translation BEFORE any other widgets are created
455
+ try:
456
+ from setiastro.saspro.i18n import load_language, get_translations_dir
457
+ ok = load_language(app=_app)
458
+ except Exception as e:
459
+ print("i18n load failed:", repr(e))
460
+
461
+
462
+ _splash_initialized = True
463
+
464
+
465
+ # Initialize splash immediately before any heavy imports
466
+ # This ensures the splash is visible while PyTorch, NumPy, etc. are loading
467
+ _init_splash()
468
+
469
+
470
+ # =============================================================================
471
+ # Now proceed with all the heavy imports (splash is visible)
472
+ # =============================================================================
473
+
474
+ # Helper to update splash during imports
475
+ def _update_splash(msg: str, progress: int):
476
+ global _splash
477
+ if _splash is not None:
478
+ _splash.setMessage(msg)
479
+ _splash.setProgress(progress)
480
+
481
+ _update_splash(QCoreApplication.translate("Splash", "Loading PyTorch runtime..."), 5)
482
+
483
+ from setiastro.saspro.runtime_torch import (
484
+ add_runtime_to_sys_path,
485
+ _ban_shadow_torch_paths,
486
+ _purge_bad_torch_from_sysmodules,
487
+ )
488
+
489
+ add_runtime_to_sys_path(status_cb=lambda *_: None)
490
+ _ban_shadow_torch_paths(status_cb=lambda *_: None)
491
+ _purge_bad_torch_from_sysmodules(status_cb=lambda *_: None)
492
+
493
+ _update_splash(QCoreApplication.translate("Splash", "Loading standard libraries..."), 10)
494
+
495
+ # ----------------------------------------
496
+ # Standard library imports (consolidated)
497
+ # ----------------------------------------
498
+ import importlib
499
+ import json
500
+ import logging
501
+ import math
502
+ import multiprocessing
503
+ import os
504
+ import re
505
+ import sys
506
+ import threading
507
+ import time
508
+ import traceback
509
+ import warnings
510
+ import webbrowser
511
+
512
+ from collections import defaultdict
513
+ from datetime import datetime
514
+ from decimal import getcontext
515
+ from io import BytesIO
516
+ from itertools import combinations
517
+ from math import isnan
518
+ from pathlib import Path
519
+ from typing import Dict, List, Optional, Set, Tuple
520
+ from urllib.parse import quote, quote_plus
521
+
522
+ _update_splash(QCoreApplication.translate("Splash", "Loading NumPy..."), 15)
523
+
524
+ # ----------------------------------------
525
+ # Third-party imports
526
+ # ----------------------------------------
527
+ import numpy as np
528
+
529
+ _update_splash(QCoreApplication.translate("Splash", "Loading image libraries..."), 20)
530
+ from tifffile import imwrite
531
+ from setiastro.saspro.xisf import XISF
532
+
533
+ _update_splash(QCoreApplication.translate("Splash", "Configuring matplotlib..."), 25)
534
+ from setiastro.saspro.config_bootstrap import ensure_mpl_config_dir
535
+ _MPL_CFG_DIR = ensure_mpl_config_dir()
536
+
537
+ # Apply metadata patches for frozen builds
538
+ from setiastro.saspro.metadata_patcher import apply_metadata_patches
539
+ apply_metadata_patches()
540
+ # ----------------------------------------
541
+
542
+ warnings.filterwarnings(
543
+ "ignore",
544
+ message=r"Call to deprecated function \(or staticmethod\) _destroy\.",
545
+ category=DeprecationWarning,
546
+ )
547
+
548
+ os.environ['LIGHTKURVE_STYLE'] = 'default'
549
+
550
+ # ----------------------------------------
551
+ # Matplotlib configuration
552
+ # ----------------------------------------
553
+ import matplotlib
554
+ matplotlib.use("QtAgg")
555
+
556
+ # Configure stdout encoding
557
+ if (sys.stdout is not None) and (hasattr(sys.stdout, "reconfigure")):
558
+ sys.stdout.reconfigure(encoding='utf-8')
559
+
560
+ # --- Lazy imports for heavy dependencies (performance optimization) ---
561
+ # photutils: loaded on first use
562
+ _photutils_isophote = None
563
+ def _get_photutils_isophote():
564
+ """Lazy loader for photutils.isophote module."""
565
+ global _photutils_isophote
566
+ if _photutils_isophote is None:
567
+ try:
568
+ from photutils import isophote as _isophote_module
569
+ _photutils_isophote = _isophote_module
570
+ except Exception:
571
+ _photutils_isophote = False # Mark as failed
572
+ return _photutils_isophote if _photutils_isophote else None
573
+
574
+ def get_Ellipse():
575
+ """Get photutils.isophote.Ellipse, loading lazily."""
576
+ mod = _get_photutils_isophote()
577
+ return mod.Ellipse if mod else None
578
+
579
+ def get_EllipseGeometry():
580
+ """Get photutils.isophote.EllipseGeometry, loading lazily."""
581
+ mod = _get_photutils_isophote()
582
+ return mod.EllipseGeometry if mod else None
583
+
584
+ def get_build_ellipse_model():
585
+ """Get photutils.isophote.build_ellipse_model, loading lazily."""
586
+ mod = _get_photutils_isophote()
587
+ return mod.build_ellipse_model if mod else None
588
+
589
+ # lightkurve: loaded on first use
590
+ _lightkurve_module = None
591
+ def get_lightkurve():
592
+ """Lazy loader for lightkurve module."""
593
+ global _lightkurve_module
594
+ if _lightkurve_module is None:
595
+ try:
596
+ import lightkurve as _lk
597
+ _lk.MPLSTYLE = None
598
+ _lightkurve_module = _lk
599
+ except Exception:
600
+ _lightkurve_module = False # Mark as failed
601
+ return _lightkurve_module if _lightkurve_module else None
602
+ # --- End lazy imports ---
603
+
604
+ _update_splash(QCoreApplication.translate("Splash", "Loading UI utilities..."), 30)
605
+
606
+ # Shared UI utilities (avoiding code duplication)
607
+ from setiastro.saspro.widgets.common_utilities import (
608
+ AboutDialog,
609
+ ProjectSaveWorker as _ProjectSaveWorker,
610
+ DECOR_GLYPHS,
611
+ _strip_ui_decorations,
612
+ install_crash_handlers,
613
+ )
614
+
615
+ _update_splash(QCoreApplication.translate("Splash", "Loading reproject library..."), 35)
616
+
617
+ # Reproject for WCS-based alignment
618
+ try:
619
+ from reproject import reproject_interp
620
+ except ImportError:
621
+ reproject_interp = None # fallback if not installed
622
+
623
+ _update_splash(QCoreApplication.translate("Splash", "Loading OpenCV..."), 40)
624
+
625
+ # OpenCV for transform estimation & warping
626
+ try:
627
+ import cv2
628
+ OPENCV_AVAILABLE = True
629
+ except ImportError:
630
+ OPENCV_AVAILABLE = False
631
+
632
+
633
+ _update_splash(QCoreApplication.translate("Splash", "Loading PyQt6 components..."), 45)
634
+
635
+ #################################
636
+ # PyQt6 Imports
637
+ #################################
638
+ from PyQt6 import sip
639
+
640
+ # ----- QtWidgets -----
641
+ from PyQt6.QtWidgets import (QDialog, QApplication, QMainWindow, QWidget, QHBoxLayout, QFileDialog, QMessageBox, QSizePolicy, QToolBar, QPushButton, QAbstractItemDelegate,
642
+ QLineEdit, QMenu, QListWidget, QListWidgetItem, QSplashScreen, QDockWidget, QListView, QCompleter, QMdiArea, QMdiSubWindow, QWidgetAction, QAbstractItemView,
643
+ QInputDialog, QVBoxLayout, QLabel, QCheckBox, QProgressBar, QProgressDialog, QGraphicsItem, QTabWidget, QTableWidget, QHeaderView, QTableWidgetItem, QToolButton, QPlainTextEdit
644
+ )
645
+
646
+ # ----- QtGui -----
647
+ from PyQt6.QtGui import (QPixmap, QColor, QIcon, QKeySequence, QShortcut, QGuiApplication, QStandardItemModel, QStandardItem, QAction, QPalette, QBrush, QActionGroup, QDesktopServices, QFont, QTextCursor
648
+ )
649
+
650
+ # ----- QtCore -----
651
+ from PyQt6.QtCore import (Qt, pyqtSignal, QCoreApplication, QTimer, QSize, QSignalBlocker, QModelIndex, QThread, QUrl, QSettings, QEvent, QByteArray, QObject,
652
+ QPropertyAnimation, QEasingCurve
653
+ )
654
+
655
+ from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply
656
+
657
+
658
+ try:
659
+ from setiastro.saspro._generated.build_info import BUILD_TIMESTAMP
660
+ except Exception:
661
+ # No generated build info → running from local source checkout
662
+ BUILD_TIMESTAMP = "dev"
663
+
664
+
665
+
666
+ _update_splash(QCoreApplication.translate("Splash", "Loading resources..."), 50)
667
+
668
+ # Icon paths are now centralized in setiastro.saspro.resources module
669
+ from setiastro.saspro.resources import (
670
+ icon_path, windowslogo_path, green_path, neutral_path, whitebalance_path,
671
+ morpho_path, clahe_path, starnet_path, staradd_path, LExtract_path,
672
+ LInsert_path, slot0_path, slot1_path, slot2_path, slot3_path, slot4_path,
673
+ rgbcombo_path, rgbextract_path, copyslot_path, graxperticon_path,
674
+ cropicon_path, openfile_path, abeicon_path, undoicon_path, redoicon_path,
675
+ blastericon_path, hdr_path, invert_path, fliphorizontal_path,
676
+ flipvertical_path, rotateclockwise_path, rotatecounterclockwise_path,
677
+ rotate180_path, maskcreate_path, maskapply_path, maskremove_path,
678
+ slot5_path, slot6_path, slot7_path, slot8_path, slot9_path, pixelmath_path,
679
+ histogram_path, mosaic_path, rescale_path, staralign_path, mask_path,
680
+ platesolve_path, psf_path, supernova_path, starregistration_path,
681
+ stacking_path, pedestal_icon_path, starspike_path, aperture_path,
682
+ jwstpupil_path, signature_icon_path, livestacking_path, hrdiagram_path,
683
+ convoicon_path, spcc_icon_path, sasp_data_path, exoicon_path, peeker_icon,
684
+ dse_icon_path, astrobin_filters_csv_path, isophote_path, statstretch_path,
685
+ starstretch_path, curves_path, disk_path, uhs_path, blink_path, ppp_path,
686
+ nbtorgb_path, freqsep_path, contsub_path, halo_path, cosmic_path,
687
+ satellite_path, imagecombine_path, wrench_path, eye_icon_path,
688
+ disk_icon_path, nuke_path, hubble_path, collage_path, annotated_path,
689
+ colorwheel_path, font_path, csv_icon_path, spinner_path, wims_path,
690
+ wimi_path, linearfit_path, debayer_path, aberration_path,
691
+ functionbundles_path, viewbundles_path, selectivecolor_path, rgbalign_path,
692
+ )
693
+
694
+
695
+ _update_splash(QCoreApplication.translate("Splash", "Configuring Qt message handler..."), 55)
696
+
697
+ from PyQt6.QtCore import qInstallMessageHandler, QtMsgType
698
+
699
+ def _qt_msg_handler(mode, ctx, msg):
700
+ lvl = {
701
+ QtMsgType.QtDebugMsg: logging.DEBUG,
702
+ QtMsgType.QtInfoMsg: logging.INFO,
703
+ QtMsgType.QtWarningMsg: logging.WARNING,
704
+ QtMsgType.QtCriticalMsg: logging.ERROR,
705
+ QtMsgType.QtFatalMsg: logging.CRITICAL,
706
+ }.get(mode, logging.ERROR)
707
+ logging.log(lvl, "Qt: %s (%s:%s)", msg, getattr(ctx, "file", "?"), getattr(ctx, "line", -1))
708
+
709
+ qInstallMessageHandler(_qt_msg_handler)
710
+
711
+ _update_splash(QCoreApplication.translate("Splash", "Loading MDI widgets..."), 60)
712
+
713
+ # MDI widgets imported from setiastro.saspro.mdi_widgets
714
+ from setiastro.saspro.mdi_widgets import (
715
+ MdiArea, ViewLinkController, ConsoleListWidget, QtLogStream, _DocProxy,
716
+ ROLE_ACTION as _ROLE_ACTION,
717
+ )
718
+
719
+ # Helper functions imported from setiastro.saspro.main_helpers
720
+ from setiastro.saspro.main_helpers import (
721
+ safe_join_dir_and_name as _safe_join_dir_and_name,
722
+ normalize_save_path_chosen_filter as _normalize_save_path_chosen_filter,
723
+ display_name as _display_name,
724
+ best_doc_name as _best_doc_name,
725
+ doc_looks_like_table as _doc_looks_like_table,
726
+ is_alive as _is_alive,
727
+ safe_widget as _safe_widget,
728
+ )
729
+
730
+ # AboutDialog, DECOR_GLYPHS, _strip_ui_decorations imported from setiastro.saspro.widgets.common_utilities
731
+
732
+ # File utilities imported from setiastro.saspro.file_utils
733
+ from setiastro.saspro.file_utils import (
734
+ _normalize_ext,
735
+ _sanitize_filename,
736
+ _exts_from_filter,
737
+ REPLACE_SPACES_WITH_UNDERSCORES as _REPLACE_SPACES_WITH_UNDERSCORES,
738
+ WIN_RESERVED_NAMES as _WIN_RESERVED,
739
+ )
740
+
741
+ _update_splash(QCoreApplication.translate("Splash", "Loading main window module..."), 65)
742
+
743
+ from setiastro.saspro.gui.main_window import AstroSuiteProMainWindow
744
+
745
+ _update_splash(QCoreApplication.translate("Splash", "Modules loaded, finalizing..."), 70)
746
+
747
+
748
+ def main():
749
+ """
750
+ Main entry point for Seti Astro Suite Pro.
751
+
752
+ This function can be called from:
753
+ - The package entry point (setiastrosuitepro command)
754
+ - Direct import and call
755
+ - When running as a module: python -m setiastro.saspro
756
+ """
757
+ global _splash, _app, _splash_initialized
758
+
759
+ # Initialize splash if not already done
760
+ if not _splash_initialized:
761
+ _init_splash()
762
+
763
+ # Update splash with build info now that we have VERSION and BUILD_TIMESTAMP
764
+ if _splash:
765
+ _splash.setBuildInfo(VERSION, BUILD_TIMESTAMP)
766
+ _splash.setMessage(QCoreApplication.translate("Splash", "Setting up logging..."))
767
+ _splash.setProgress(72)
768
+
769
+ # --- Logging (catch unhandled exceptions to a file) ---
770
+ import tempfile
771
+ from pathlib import Path
772
+
773
+ # Cross-platform log file location
774
+ def get_log_file_path():
775
+ """Get appropriate log file path for the current platform."""
776
+
777
+ if hasattr(sys, '_MEIPASS'):
778
+ # Running in PyInstaller bundle - use platform-appropriate user directory
779
+ if sys.platform.startswith('win'):
780
+ # Windows: %APPDATA%\SetiAstroSuitePro\logs\
781
+ log_dir = Path(os.path.expandvars('%APPDATA%')) / 'SetiAstroSuitePro' / 'logs'
782
+ elif sys.platform.startswith('darwin'):
783
+ # macOS: ~/Library/Logs/SetiAstroSuitePro/
784
+ log_dir = Path.home() / 'Library' / 'Logs' / 'SetiAstroSuitePro'
785
+ else:
786
+ # Linux: ~/.local/share/SetiAstroSuitePro/logs/
787
+ log_dir = Path.home() / '.local' / 'share' / 'SetiAstroSuitePro' / 'logs'
788
+
789
+ # Create directory if it doesn't exist
790
+ try:
791
+ log_dir.mkdir(parents=True, exist_ok=True)
792
+ log_file = log_dir / 'saspro.log'
793
+ except (OSError, PermissionError):
794
+ # Fallback to temp directory if user directory fails
795
+ log_file = Path(tempfile.gettempdir()) / 'saspro.log'
796
+ else:
797
+ # Development mode - use logs folder in project
798
+ log_dir = Path('logs')
799
+ try:
800
+ log_dir.mkdir(parents=True, exist_ok=True)
801
+ log_file = log_dir / 'saspro.log'
802
+ except (OSError, PermissionError):
803
+ log_file = Path('saspro.log')
804
+
805
+ return str(log_file)
806
+
807
+ # Configure logging with cross-platform path
808
+ log_file_path = get_log_file_path()
809
+
810
+ try:
811
+ logging.basicConfig(
812
+ filename=log_file_path,
813
+ level=logging.INFO,
814
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
815
+ filemode='a' # Append mode
816
+ )
817
+ logging.info(f"Logging to: {log_file_path}")
818
+ logging.info(f"Platform: {sys.platform}")
819
+ logging.info(f"PyInstaller bundle: {hasattr(sys, '_MEIPASS')}")
820
+ except Exception as e:
821
+ # Ultimate fallback - console only logging
822
+ logging.basicConfig(
823
+ level=logging.INFO,
824
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
825
+ handlers=[logging.StreamHandler(sys.stdout)]
826
+ )
827
+ print(f"Warning: Could not write to log file {log_file_path}: {e}")
828
+ print("Using console-only logging")
829
+
830
+
831
+ # Setup crash handlers and app icon
832
+ if _splash:
833
+ _splash.setMessage(QCoreApplication.translate("Splash", "Installing crash handlers..."))
834
+ _splash.setProgress(75)
835
+ install_crash_handlers(_app)
836
+ _app.setWindowIcon(QIcon(windowslogo_path if os.path.exists(windowslogo_path) else icon_path))
837
+
838
+ # --- Windows exe / multiprocessing friendly ---
839
+ if _splash:
840
+ _splash.setMessage(QCoreApplication.translate("Splash", "Configuring multiprocessing..."))
841
+ _splash.setProgress(78)
842
+ try:
843
+ multiprocessing.freeze_support()
844
+ try:
845
+ multiprocessing.set_start_method("spawn", force=True)
846
+ except RuntimeError:
847
+ # Already set in this interpreter
848
+ pass
849
+ except Exception:
850
+ logging.exception("Multiprocessing init failed (continuing).")
851
+
852
+ try:
853
+ if _splash:
854
+ _splash.setMessage(QCoreApplication.translate("Splash", "Loading image manager..."))
855
+ _splash.setProgress(80)
856
+ from setiastro.saspro.legacy.image_manager import ImageManager
857
+
858
+ if _splash:
859
+ _splash.setMessage(QCoreApplication.translate("Splash", "Suppressing warnings..."))
860
+ _splash.setProgress(82)
861
+ from matplotlib import MatplotlibDeprecationWarning
862
+ warnings.filterwarnings("ignore", category=MatplotlibDeprecationWarning)
863
+
864
+ if _splash:
865
+ _splash.setMessage(QCoreApplication.translate("Splash", "Creating image manager..."))
866
+ _splash.setProgress(85)
867
+ imgr = ImageManager(max_slots=100)
868
+
869
+ if _splash:
870
+ _splash.setMessage(QCoreApplication.translate("Splash", "Building main window..."))
871
+ _splash.setProgress(90)
872
+ win = AstroSuiteProMainWindow(
873
+ image_manager=imgr,
874
+ version=VERSION,
875
+ build_timestamp=BUILD_TIMESTAMP,
876
+ )
877
+
878
+ if _splash:
879
+ _splash.setMessage(QCoreApplication.translate("Splash", "Showing main window..."))
880
+ _splash.setProgress(95)
881
+
882
+ # --- Smooth Transition: App Fade In + Splash Fade Out ---
883
+ # MITIGATION: Prevent "White Flash" on startup
884
+ # 1. Force a dark background immediately so if opacity lags, it's dark not white
885
+ win.setStyleSheet("QMainWindow { background-color: #0F0F19; }")
886
+ # 2. Ensure native window handle exists so setWindowOpacity works immediately
887
+ win.winId()
888
+ # 3. Set opacity to 0
889
+ win.setWindowOpacity(0.0)
890
+
891
+ win.show()
892
+
893
+ # 1. Animate Main Window Fade In
894
+ anim_app = QPropertyAnimation(win, b"windowOpacity")
895
+ anim_app.setDuration(1200)
896
+ anim_app.setStartValue(0.0)
897
+ anim_app.setEndValue(1.0)
898
+ anim_app.setEasingCurve(QEasingCurve.Type.OutQuad)
899
+
900
+ # Cleanup temp stylesheet upon completion to avoid interfering with ThemeMixin
901
+ def _on_fade_in_finished():
902
+ win.setStyleSheet("")
903
+ if hasattr(win, "on_fade_in_complete"):
904
+ win.on_fade_in_complete()
905
+
906
+ anim_app.finished.connect(_on_fade_in_finished)
907
+ anim_app.start()
908
+
909
+ # Start background Numba warmup after UI is visible
910
+ try:
911
+ from setiastro.saspro.numba_warmup import start_background_warmup
912
+ start_background_warmup()
913
+ except Exception:
914
+ pass # Non-critical if warmup fails
915
+
916
+ if _splash:
917
+ _splash.setMessage(QCoreApplication.translate("Splash", "Ready!"))
918
+ _splash.setProgress(100)
919
+ _app.processEvents()
920
+
921
+ # Small delay to ensure "Ready!" is seen briefly before fade starts
922
+ import time
923
+ time.sleep(0.1)
924
+
925
+ # 2. Animate Splash Fade Out
926
+ # Note: We do NOT use finish() directly here. The animation calls it when done.
927
+ _splash.start_fade_out()
928
+
929
+ # NOTE: We keep a reference to _splash (global) so it doesn't get GC'd during animation.
930
+ # It will deleteLater() itself.
931
+
932
+ if BUILD_TIMESTAMP == "dev":
933
+ build_label = "running from local source code"
934
+ else:
935
+ build_label = f"build {BUILD_TIMESTAMP}"
936
+
937
+ print(f"Seti Astro Suite Pro v{VERSION} ({build_label}) up and running!")
938
+ sys.exit(_app.exec())
939
+
940
+ except Exception:
941
+ import traceback
942
+ if _splash:
943
+ try:
944
+ _splash.hide()
945
+ _splash.close()
946
+ _splash.deleteLater()
947
+ except Exception:
948
+ pass
949
+ tb = traceback.format_exc()
950
+ logging.error("Unhandled exception occurred\n%s", tb)
951
+ msg = QMessageBox(None)
952
+ msg.setIcon(QMessageBox.Icon.Critical)
953
+ msg.setWindowTitle(QCoreApplication.translate("Main", "Application Error"))
954
+ msg.setText(QCoreApplication.translate("Main", "An unexpected error occurred."))
955
+ msg.setInformativeText(tb.splitlines()[-1] if tb else "See details.")
956
+ msg.setDetailedText(tb)
957
+ msg.setStandardButtons(QMessageBox.StandardButton.Ok)
958
+ msg.exec()
959
+ sys.exit(1)
960
+
961
+
962
+ # When run as a module, execute main()
963
+ if __name__ == "__main__":
964
+ main()