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.
- setiastro/__init__.py +2 -0
- setiastro/data/SASP_data.fits +0 -0
- setiastro/data/catalogs/List_of_Galaxies_with_Distances_Gly.csv +488 -0
- setiastro/data/catalogs/astrobin_filters.csv +890 -0
- setiastro/data/catalogs/astrobin_filters_page1_local.csv +51 -0
- setiastro/data/catalogs/cali2.csv +63 -0
- setiastro/data/catalogs/cali2color.csv +65 -0
- setiastro/data/catalogs/celestial_catalog - original.csv +16471 -0
- setiastro/data/catalogs/celestial_catalog.csv +24031 -0
- setiastro/data/catalogs/detected_stars.csv +24784 -0
- setiastro/data/catalogs/fits_header_data.csv +46 -0
- setiastro/data/catalogs/test.csv +8 -0
- setiastro/data/catalogs/updated_celestial_catalog.csv +16471 -0
- setiastro/images/Astro_Spikes.png +0 -0
- setiastro/images/Background_startup.jpg +0 -0
- setiastro/images/HRDiagram.png +0 -0
- setiastro/images/LExtract.png +0 -0
- setiastro/images/LInsert.png +0 -0
- setiastro/images/Oxygenation-atm-2.svg.png +0 -0
- setiastro/images/RGB080604.png +0 -0
- setiastro/images/abeicon.png +0 -0
- setiastro/images/aberration.png +0 -0
- setiastro/images/acv_icon.png +0 -0
- setiastro/images/andromedatry.png +0 -0
- setiastro/images/andromedatry_satellited.png +0 -0
- setiastro/images/annotated.png +0 -0
- setiastro/images/aperture.png +0 -0
- setiastro/images/astrosuite.ico +0 -0
- setiastro/images/astrosuite.png +0 -0
- setiastro/images/astrosuitepro.icns +0 -0
- setiastro/images/astrosuitepro.ico +0 -0
- setiastro/images/astrosuitepro.png +0 -0
- setiastro/images/background.png +0 -0
- setiastro/images/background2.png +0 -0
- setiastro/images/benchmark.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline.png +0 -0
- setiastro/images/big_moon_stabilizer_timeline_clean.png +0 -0
- setiastro/images/blaster.png +0 -0
- setiastro/images/blink.png +0 -0
- setiastro/images/clahe.png +0 -0
- setiastro/images/collage.png +0 -0
- setiastro/images/colorwheel.png +0 -0
- setiastro/images/contsub.png +0 -0
- setiastro/images/convo.png +0 -0
- setiastro/images/copyslot.png +0 -0
- setiastro/images/cosmic.png +0 -0
- setiastro/images/cosmicsat.png +0 -0
- setiastro/images/crop1.png +0 -0
- setiastro/images/cropicon.png +0 -0
- setiastro/images/curves.png +0 -0
- setiastro/images/cvs.png +0 -0
- setiastro/images/debayer.png +0 -0
- setiastro/images/denoise_cnn_custom.png +0 -0
- setiastro/images/denoise_cnn_graph.png +0 -0
- setiastro/images/disk.png +0 -0
- setiastro/images/dse.png +0 -0
- setiastro/images/exoicon.png +0 -0
- setiastro/images/eye.png +0 -0
- setiastro/images/first_quarter.png +0 -0
- setiastro/images/fliphorizontal.png +0 -0
- setiastro/images/flipvertical.png +0 -0
- setiastro/images/font.png +0 -0
- setiastro/images/freqsep.png +0 -0
- setiastro/images/full_moon.png +0 -0
- setiastro/images/functionbundle.png +0 -0
- setiastro/images/graxpert.png +0 -0
- setiastro/images/green.png +0 -0
- setiastro/images/gridicon.png +0 -0
- setiastro/images/halo.png +0 -0
- setiastro/images/hdr.png +0 -0
- setiastro/images/histogram.png +0 -0
- setiastro/images/hubble.png +0 -0
- setiastro/images/imagecombine.png +0 -0
- setiastro/images/invert.png +0 -0
- setiastro/images/isophote.png +0 -0
- setiastro/images/isophote_demo_figure.png +0 -0
- setiastro/images/isophote_demo_image.png +0 -0
- setiastro/images/isophote_demo_model.png +0 -0
- setiastro/images/isophote_demo_residual.png +0 -0
- setiastro/images/jwstpupil.png +0 -0
- setiastro/images/last_quarter.png +0 -0
- setiastro/images/linearfit.png +0 -0
- setiastro/images/livestacking.png +0 -0
- setiastro/images/mask.png +0 -0
- setiastro/images/maskapply.png +0 -0
- setiastro/images/maskcreate.png +0 -0
- setiastro/images/maskremove.png +0 -0
- setiastro/images/morpho.png +0 -0
- setiastro/images/mosaic.png +0 -0
- setiastro/images/multiscale_decomp.png +0 -0
- setiastro/images/nbtorgb.png +0 -0
- setiastro/images/neutral.png +0 -0
- setiastro/images/new_moon.png +0 -0
- setiastro/images/nuke.png +0 -0
- setiastro/images/openfile.png +0 -0
- setiastro/images/pedestal.png +0 -0
- setiastro/images/pen.png +0 -0
- setiastro/images/pixelmath.png +0 -0
- setiastro/images/platesolve.png +0 -0
- setiastro/images/ppp.png +0 -0
- setiastro/images/pro.png +0 -0
- setiastro/images/project.png +0 -0
- setiastro/images/psf.png +0 -0
- setiastro/images/redo.png +0 -0
- setiastro/images/redoicon.png +0 -0
- setiastro/images/rescale.png +0 -0
- setiastro/images/rgbalign.png +0 -0
- setiastro/images/rgbcombo.png +0 -0
- setiastro/images/rgbextract.png +0 -0
- setiastro/images/rotate180.png +0 -0
- setiastro/images/rotatearbitrary.png +0 -0
- setiastro/images/rotateclockwise.png +0 -0
- setiastro/images/rotatecounterclockwise.png +0 -0
- setiastro/images/satellite.png +0 -0
- setiastro/images/script.png +0 -0
- setiastro/images/selectivecolor.png +0 -0
- setiastro/images/simbad.png +0 -0
- setiastro/images/slot0.png +0 -0
- setiastro/images/slot1.png +0 -0
- setiastro/images/slot2.png +0 -0
- setiastro/images/slot3.png +0 -0
- setiastro/images/slot4.png +0 -0
- setiastro/images/slot5.png +0 -0
- setiastro/images/slot6.png +0 -0
- setiastro/images/slot7.png +0 -0
- setiastro/images/slot8.png +0 -0
- setiastro/images/slot9.png +0 -0
- setiastro/images/spcc.png +0 -0
- setiastro/images/spin_precession_vs_lunar_distance.png +0 -0
- setiastro/images/spinner.gif +0 -0
- setiastro/images/stacking.png +0 -0
- setiastro/images/staradd.png +0 -0
- setiastro/images/staralign.png +0 -0
- setiastro/images/starnet.png +0 -0
- setiastro/images/starregistration.png +0 -0
- setiastro/images/starspike.png +0 -0
- setiastro/images/starstretch.png +0 -0
- setiastro/images/statstretch.png +0 -0
- setiastro/images/supernova.png +0 -0
- setiastro/images/uhs.png +0 -0
- setiastro/images/undoicon.png +0 -0
- setiastro/images/upscale.png +0 -0
- setiastro/images/viewbundle.png +0 -0
- setiastro/images/waning_crescent_1.png +0 -0
- setiastro/images/waning_crescent_2.png +0 -0
- setiastro/images/waning_crescent_3.png +0 -0
- setiastro/images/waning_crescent_4.png +0 -0
- setiastro/images/waning_crescent_5.png +0 -0
- setiastro/images/waning_gibbous_1.png +0 -0
- setiastro/images/waning_gibbous_2.png +0 -0
- setiastro/images/waning_gibbous_3.png +0 -0
- setiastro/images/waning_gibbous_4.png +0 -0
- setiastro/images/waning_gibbous_5.png +0 -0
- setiastro/images/waxing_crescent_1.png +0 -0
- setiastro/images/waxing_crescent_2.png +0 -0
- setiastro/images/waxing_crescent_3.png +0 -0
- setiastro/images/waxing_crescent_4.png +0 -0
- setiastro/images/waxing_crescent_5.png +0 -0
- setiastro/images/waxing_gibbous_1.png +0 -0
- setiastro/images/waxing_gibbous_2.png +0 -0
- setiastro/images/waxing_gibbous_3.png +0 -0
- setiastro/images/waxing_gibbous_4.png +0 -0
- setiastro/images/waxing_gibbous_5.png +0 -0
- setiastro/images/whitebalance.png +0 -0
- setiastro/images/wimi_icon_256x256.png +0 -0
- setiastro/images/wimilogo.png +0 -0
- setiastro/images/wims.png +0 -0
- setiastro/images/wrench_icon.png +0 -0
- setiastro/images/xisfliberator.png +0 -0
- setiastro/qml/ResourceMonitor.qml +128 -0
- setiastro/saspro/__init__.py +20 -0
- setiastro/saspro/__main__.py +964 -0
- setiastro/saspro/_generated/__init__.py +7 -0
- setiastro/saspro/_generated/build_info.py +3 -0
- setiastro/saspro/abe.py +1379 -0
- setiastro/saspro/abe_preset.py +196 -0
- setiastro/saspro/aberration_ai.py +910 -0
- setiastro/saspro/aberration_ai_preset.py +224 -0
- setiastro/saspro/accel_installer.py +218 -0
- setiastro/saspro/accel_workers.py +30 -0
- setiastro/saspro/acv_exporter.py +379 -0
- setiastro/saspro/add_stars.py +627 -0
- setiastro/saspro/astrobin_exporter.py +1010 -0
- setiastro/saspro/astrospike.py +153 -0
- setiastro/saspro/astrospike_python.py +1841 -0
- setiastro/saspro/autostretch.py +198 -0
- setiastro/saspro/backgroundneutral.py +639 -0
- setiastro/saspro/batch_convert.py +328 -0
- setiastro/saspro/batch_renamer.py +522 -0
- setiastro/saspro/blemish_blaster.py +494 -0
- setiastro/saspro/blink_comparator_pro.py +3149 -0
- setiastro/saspro/bundles.py +61 -0
- setiastro/saspro/bundles_dock.py +114 -0
- setiastro/saspro/cheat_sheet.py +213 -0
- setiastro/saspro/clahe.py +371 -0
- setiastro/saspro/comet_stacking.py +1442 -0
- setiastro/saspro/common_tr.py +107 -0
- setiastro/saspro/config.py +38 -0
- setiastro/saspro/config_bootstrap.py +40 -0
- setiastro/saspro/config_manager.py +316 -0
- setiastro/saspro/continuum_subtract.py +1620 -0
- setiastro/saspro/convo.py +1403 -0
- setiastro/saspro/convo_preset.py +414 -0
- setiastro/saspro/copyastro.py +190 -0
- setiastro/saspro/cosmicclarity.py +1593 -0
- setiastro/saspro/cosmicclarity_preset.py +407 -0
- setiastro/saspro/crop_dialog_pro.py +1005 -0
- setiastro/saspro/crop_preset.py +189 -0
- setiastro/saspro/curve_editor_pro.py +2608 -0
- setiastro/saspro/curves_preset.py +375 -0
- setiastro/saspro/debayer.py +673 -0
- setiastro/saspro/debug_utils.py +29 -0
- setiastro/saspro/dnd_mime.py +35 -0
- setiastro/saspro/doc_manager.py +2727 -0
- setiastro/saspro/exoplanet_detector.py +2258 -0
- setiastro/saspro/file_utils.py +284 -0
- setiastro/saspro/fitsmodifier.py +748 -0
- setiastro/saspro/fix_bom.py +32 -0
- setiastro/saspro/free_torch_memory.py +48 -0
- setiastro/saspro/frequency_separation.py +1352 -0
- setiastro/saspro/function_bundle.py +1596 -0
- setiastro/saspro/generate_translations.py +3092 -0
- setiastro/saspro/ghs_dialog_pro.py +728 -0
- setiastro/saspro/ghs_preset.py +284 -0
- setiastro/saspro/graxpert.py +638 -0
- setiastro/saspro/graxpert_preset.py +287 -0
- setiastro/saspro/gui/__init__.py +0 -0
- setiastro/saspro/gui/main_window.py +8928 -0
- setiastro/saspro/gui/mixins/__init__.py +33 -0
- setiastro/saspro/gui/mixins/dock_mixin.py +375 -0
- setiastro/saspro/gui/mixins/file_mixin.py +450 -0
- setiastro/saspro/gui/mixins/geometry_mixin.py +503 -0
- setiastro/saspro/gui/mixins/header_mixin.py +441 -0
- setiastro/saspro/gui/mixins/mask_mixin.py +421 -0
- setiastro/saspro/gui/mixins/menu_mixin.py +391 -0
- setiastro/saspro/gui/mixins/theme_mixin.py +367 -0
- setiastro/saspro/gui/mixins/toolbar_mixin.py +1824 -0
- setiastro/saspro/gui/mixins/update_mixin.py +323 -0
- setiastro/saspro/gui/mixins/view_mixin.py +477 -0
- setiastro/saspro/gui/statistics_dialog.py +47 -0
- setiastro/saspro/halobgon.py +492 -0
- setiastro/saspro/header_viewer.py +448 -0
- setiastro/saspro/headless_utils.py +88 -0
- setiastro/saspro/histogram.py +760 -0
- setiastro/saspro/history_explorer.py +941 -0
- setiastro/saspro/i18n.py +168 -0
- setiastro/saspro/image_combine.py +421 -0
- setiastro/saspro/image_peeker_pro.py +1608 -0
- setiastro/saspro/imageops/__init__.py +37 -0
- setiastro/saspro/imageops/mdi_snap.py +292 -0
- setiastro/saspro/imageops/scnr.py +36 -0
- setiastro/saspro/imageops/starbasedwhitebalance.py +210 -0
- setiastro/saspro/imageops/stretch.py +236 -0
- setiastro/saspro/isophote.py +1186 -0
- setiastro/saspro/layers.py +208 -0
- setiastro/saspro/layers_dock.py +714 -0
- setiastro/saspro/lazy_imports.py +193 -0
- setiastro/saspro/legacy/__init__.py +2 -0
- setiastro/saspro/legacy/image_manager.py +2360 -0
- setiastro/saspro/legacy/numba_utils.py +3676 -0
- setiastro/saspro/legacy/xisf.py +1213 -0
- setiastro/saspro/linear_fit.py +537 -0
- setiastro/saspro/live_stacking.py +1854 -0
- setiastro/saspro/log_bus.py +5 -0
- setiastro/saspro/logging_config.py +460 -0
- setiastro/saspro/luminancerecombine.py +510 -0
- setiastro/saspro/main_helpers.py +201 -0
- setiastro/saspro/mask_creation.py +1090 -0
- setiastro/saspro/masks_core.py +56 -0
- setiastro/saspro/mdi_widgets.py +353 -0
- setiastro/saspro/memory_utils.py +666 -0
- setiastro/saspro/metadata_patcher.py +75 -0
- setiastro/saspro/mfdeconv.py +3909 -0
- setiastro/saspro/mfdeconv_earlystop.py +71 -0
- setiastro/saspro/mfdeconvcudnn.py +3312 -0
- setiastro/saspro/mfdeconvsport.py +2459 -0
- setiastro/saspro/minorbodycatalog.py +567 -0
- setiastro/saspro/morphology.py +411 -0
- setiastro/saspro/multiscale_decomp.py +1751 -0
- setiastro/saspro/nbtorgb_stars.py +541 -0
- setiastro/saspro/numba_utils.py +3145 -0
- setiastro/saspro/numba_warmup.py +141 -0
- setiastro/saspro/ops/__init__.py +9 -0
- setiastro/saspro/ops/command_help_dialog.py +623 -0
- setiastro/saspro/ops/command_runner.py +217 -0
- setiastro/saspro/ops/commands.py +1594 -0
- setiastro/saspro/ops/script_editor.py +1105 -0
- setiastro/saspro/ops/scripts.py +1476 -0
- setiastro/saspro/ops/settings.py +637 -0
- setiastro/saspro/parallel_utils.py +554 -0
- setiastro/saspro/pedestal.py +121 -0
- setiastro/saspro/perfect_palette_picker.py +1105 -0
- setiastro/saspro/pipeline.py +110 -0
- setiastro/saspro/pixelmath.py +1604 -0
- setiastro/saspro/plate_solver.py +2480 -0
- setiastro/saspro/project_io.py +797 -0
- setiastro/saspro/psf_utils.py +136 -0
- setiastro/saspro/psf_viewer.py +631 -0
- setiastro/saspro/pyi_rthook_astroquery.py +95 -0
- setiastro/saspro/remove_green.py +331 -0
- setiastro/saspro/remove_stars.py +1599 -0
- setiastro/saspro/remove_stars_preset.py +446 -0
- setiastro/saspro/resources.py +570 -0
- setiastro/saspro/rgb_combination.py +208 -0
- setiastro/saspro/rgb_extract.py +19 -0
- setiastro/saspro/rgbalign.py +727 -0
- setiastro/saspro/runtime_imports.py +7 -0
- setiastro/saspro/runtime_torch.py +754 -0
- setiastro/saspro/save_options.py +73 -0
- setiastro/saspro/selective_color.py +1614 -0
- setiastro/saspro/sfcc.py +1530 -0
- setiastro/saspro/shortcuts.py +3125 -0
- setiastro/saspro/signature_insert.py +1106 -0
- setiastro/saspro/stacking_suite.py +19069 -0
- setiastro/saspro/star_alignment.py +7383 -0
- setiastro/saspro/star_alignment_preset.py +329 -0
- setiastro/saspro/star_metrics.py +49 -0
- setiastro/saspro/star_spikes.py +769 -0
- setiastro/saspro/star_stretch.py +542 -0
- setiastro/saspro/stat_stretch.py +554 -0
- setiastro/saspro/status_log_dock.py +78 -0
- setiastro/saspro/subwindow.py +3523 -0
- setiastro/saspro/supernovaasteroidhunter.py +1719 -0
- setiastro/saspro/swap_manager.py +134 -0
- setiastro/saspro/torch_backend.py +89 -0
- setiastro/saspro/torch_rejection.py +434 -0
- setiastro/saspro/translations/all_source_strings.json +4726 -0
- setiastro/saspro/translations/ar_translations.py +4096 -0
- setiastro/saspro/translations/de_translations.py +3728 -0
- setiastro/saspro/translations/es_translations.py +4169 -0
- setiastro/saspro/translations/fr_translations.py +4090 -0
- setiastro/saspro/translations/hi_translations.py +3803 -0
- setiastro/saspro/translations/integrate_translations.py +271 -0
- setiastro/saspro/translations/it_translations.py +4728 -0
- setiastro/saspro/translations/ja_translations.py +3834 -0
- setiastro/saspro/translations/pt_translations.py +3847 -0
- setiastro/saspro/translations/ru_translations.py +3082 -0
- setiastro/saspro/translations/saspro_ar.qm +0 -0
- setiastro/saspro/translations/saspro_ar.ts +16019 -0
- setiastro/saspro/translations/saspro_de.qm +0 -0
- setiastro/saspro/translations/saspro_de.ts +14548 -0
- setiastro/saspro/translations/saspro_es.qm +0 -0
- setiastro/saspro/translations/saspro_es.ts +16202 -0
- setiastro/saspro/translations/saspro_fr.qm +0 -0
- setiastro/saspro/translations/saspro_fr.ts +15870 -0
- setiastro/saspro/translations/saspro_hi.qm +0 -0
- setiastro/saspro/translations/saspro_hi.ts +14855 -0
- setiastro/saspro/translations/saspro_it.qm +0 -0
- setiastro/saspro/translations/saspro_it.ts +19046 -0
- setiastro/saspro/translations/saspro_ja.qm +0 -0
- setiastro/saspro/translations/saspro_ja.ts +14980 -0
- setiastro/saspro/translations/saspro_pt.qm +0 -0
- setiastro/saspro/translations/saspro_pt.ts +15024 -0
- setiastro/saspro/translations/saspro_ru.qm +0 -0
- setiastro/saspro/translations/saspro_ru.ts +11835 -0
- setiastro/saspro/translations/saspro_sw.qm +0 -0
- setiastro/saspro/translations/saspro_sw.ts +15237 -0
- setiastro/saspro/translations/saspro_uk.qm +0 -0
- setiastro/saspro/translations/saspro_uk.ts +15248 -0
- setiastro/saspro/translations/saspro_zh.qm +0 -0
- setiastro/saspro/translations/saspro_zh.ts +15289 -0
- setiastro/saspro/translations/sw_translations.py +3897 -0
- setiastro/saspro/translations/uk_translations.py +3929 -0
- setiastro/saspro/translations/zh_translations.py +3910 -0
- setiastro/saspro/versioning.py +77 -0
- setiastro/saspro/view_bundle.py +1558 -0
- setiastro/saspro/wavescale_hdr.py +648 -0
- setiastro/saspro/wavescale_hdr_preset.py +101 -0
- setiastro/saspro/wavescalede.py +683 -0
- setiastro/saspro/wavescalede_preset.py +230 -0
- setiastro/saspro/wcs_update.py +374 -0
- setiastro/saspro/whitebalance.py +540 -0
- setiastro/saspro/widgets/__init__.py +48 -0
- setiastro/saspro/widgets/common_utilities.py +306 -0
- setiastro/saspro/widgets/graphics_views.py +122 -0
- setiastro/saspro/widgets/image_utils.py +518 -0
- setiastro/saspro/widgets/minigame/game.js +991 -0
- setiastro/saspro/widgets/minigame/index.html +53 -0
- setiastro/saspro/widgets/minigame/style.css +241 -0
- setiastro/saspro/widgets/preview_dialogs.py +280 -0
- setiastro/saspro/widgets/resource_monitor.py +313 -0
- setiastro/saspro/widgets/spinboxes.py +290 -0
- setiastro/saspro/widgets/themed_buttons.py +13 -0
- setiastro/saspro/widgets/wavelet_utils.py +331 -0
- setiastro/saspro/wimi.py +7367 -0
- setiastro/saspro/wims.py +588 -0
- setiastro/saspro/window_shelf.py +185 -0
- setiastro/saspro/xisf.py +1213 -0
- setiastrosuitepro-1.6.7.dist-info/METADATA +279 -0
- setiastrosuitepro-1.6.7.dist-info/RECORD +394 -0
- setiastrosuitepro-1.6.7.dist-info/WHEEL +4 -0
- setiastrosuitepro-1.6.7.dist-info/entry_points.txt +6 -0
- setiastrosuitepro-1.6.7.dist-info/licenses/LICENSE +674 -0
- setiastrosuitepro-1.6.7.dist-info/licenses/license.txt +2580 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"""
|
|
2
|
+
File utilities for Seti Astro Suite Pro.
|
|
3
|
+
|
|
4
|
+
This module provides centralized file handling utilities to avoid
|
|
5
|
+
code duplication across the codebase.
|
|
6
|
+
|
|
7
|
+
Included:
|
|
8
|
+
- Extension normalization
|
|
9
|
+
- Filename sanitization
|
|
10
|
+
- Path utilities
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import os
|
|
16
|
+
import re
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Optional, List, Set
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
# ---------------------------------------------------------------------------
|
|
22
|
+
# Constants
|
|
23
|
+
# ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
# Whether to replace spaces with underscores in filenames
|
|
26
|
+
REPLACE_SPACES_WITH_UNDERSCORES = True
|
|
27
|
+
|
|
28
|
+
# Windows reserved device names
|
|
29
|
+
WIN_RESERVED_NAMES: Set[str] = {
|
|
30
|
+
"CON", "PRN", "AUX", "NUL",
|
|
31
|
+
*(f"COM{i}" for i in range(1, 10)),
|
|
32
|
+
*(f"LPT{i}" for i in range(1, 10)),
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
# Extension normalization mappings
|
|
36
|
+
EXT_ALIASES = {
|
|
37
|
+
"jpeg": "jpg",
|
|
38
|
+
"tiff": "tif",
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# Allowed bit depths per format
|
|
42
|
+
ALLOWED_BIT_DEPTHS = {
|
|
43
|
+
"png": {"8-bit"},
|
|
44
|
+
"jpg": {"8-bit"},
|
|
45
|
+
"fits": {"32-bit floating point"},
|
|
46
|
+
"fit": {"32-bit floating point"},
|
|
47
|
+
"tif": {"8-bit", "16-bit", "32-bit unsigned", "32-bit floating point"},
|
|
48
|
+
"xisf": {"16-bit", "32-bit unsigned", "32-bit floating point"},
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# ---------------------------------------------------------------------------
|
|
53
|
+
# Extension Normalization
|
|
54
|
+
# ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
def normalize_ext(ext: str) -> str:
|
|
57
|
+
"""
|
|
58
|
+
Normalize a file extension to its canonical form.
|
|
59
|
+
|
|
60
|
+
- Converts to lowercase
|
|
61
|
+
- Removes leading dot
|
|
62
|
+
- Converts aliases (jpeg→jpg, tiff→tif)
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
ext: Extension string (with or without leading dot)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Normalized extension without leading dot
|
|
69
|
+
|
|
70
|
+
Example:
|
|
71
|
+
>>> normalize_ext(".JPEG")
|
|
72
|
+
'jpg'
|
|
73
|
+
>>> normalize_ext("TIFF")
|
|
74
|
+
'tif'
|
|
75
|
+
>>> normalize_ext(".png")
|
|
76
|
+
'png'
|
|
77
|
+
"""
|
|
78
|
+
e = ext.lower().lstrip(".")
|
|
79
|
+
return EXT_ALIASES.get(e, e)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
# Alias for backward compatibility
|
|
83
|
+
_normalize_ext = normalize_ext
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
# ---------------------------------------------------------------------------
|
|
87
|
+
# Filename Sanitization
|
|
88
|
+
# ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
def sanitize_filename(
|
|
91
|
+
basename: str,
|
|
92
|
+
replace_spaces: bool = REPLACE_SPACES_WITH_UNDERSCORES
|
|
93
|
+
) -> str:
|
|
94
|
+
"""
|
|
95
|
+
Sanitize a filename for cross-platform compatibility.
|
|
96
|
+
|
|
97
|
+
Handles:
|
|
98
|
+
- Collapsed/trimmed whitespace
|
|
99
|
+
- Optional spaces→underscores conversion
|
|
100
|
+
- Illegal characters removed (Windows/macOS/Linux superset)
|
|
101
|
+
- No leading/trailing dots/spaces
|
|
102
|
+
- Windows reserved device names avoided by appending '_'
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
basename: The filename to sanitize (without directory path)
|
|
106
|
+
replace_spaces: Whether to replace spaces with underscores
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Sanitized filename
|
|
110
|
+
|
|
111
|
+
Example:
|
|
112
|
+
>>> sanitize_filename("my file: test?.png")
|
|
113
|
+
'my_file_test.png'
|
|
114
|
+
>>> sanitize_filename("CON.txt")
|
|
115
|
+
'CON_.txt'
|
|
116
|
+
"""
|
|
117
|
+
name = (basename or "").strip()
|
|
118
|
+
|
|
119
|
+
# Split name/ext carefully
|
|
120
|
+
stem, ext = os.path.splitext(name)
|
|
121
|
+
|
|
122
|
+
# Collapse weird whitespace in stem
|
|
123
|
+
stem = " ".join(stem.split())
|
|
124
|
+
|
|
125
|
+
# Replace spaces if requested
|
|
126
|
+
if replace_spaces and stem:
|
|
127
|
+
stem = stem.replace(" ", "_")
|
|
128
|
+
|
|
129
|
+
# Remove illegal characters (Windows/macOS/Linux superset)
|
|
130
|
+
# Illegal: < > : " / \ | ? * and control characters
|
|
131
|
+
stem = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '', stem)
|
|
132
|
+
ext = re.sub(r'[<>:"/\\|?*\x00-\x1f]', '', ext)
|
|
133
|
+
|
|
134
|
+
# Strip leading/trailing dots and spaces from stem
|
|
135
|
+
stem = stem.strip(". ")
|
|
136
|
+
|
|
137
|
+
# Handle Windows reserved names
|
|
138
|
+
stem_upper = stem.upper()
|
|
139
|
+
if stem_upper in WIN_RESERVED_NAMES:
|
|
140
|
+
stem = stem + "_"
|
|
141
|
+
|
|
142
|
+
# Also check stem without extension for reserved names
|
|
143
|
+
stem_base_upper = stem_upper.split(".")[0] if "." in stem_upper else stem_upper
|
|
144
|
+
if stem_base_upper in WIN_RESERVED_NAMES and stem_upper != stem_base_upper:
|
|
145
|
+
stem = stem + "_"
|
|
146
|
+
|
|
147
|
+
# Combine stem and extension
|
|
148
|
+
if ext:
|
|
149
|
+
return stem + ext
|
|
150
|
+
return stem if stem else "unnamed"
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# Alias for backward compatibility
|
|
154
|
+
_sanitize_filename = sanitize_filename
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
# ---------------------------------------------------------------------------
|
|
158
|
+
# Path Utilities
|
|
159
|
+
# ---------------------------------------------------------------------------
|
|
160
|
+
|
|
161
|
+
def get_unique_path(path: str) -> str:
|
|
162
|
+
"""
|
|
163
|
+
Get a unique file path by appending a number if the file exists.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
path: Original file path
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Unique path (original if doesn't exist, or with _1, _2, etc.)
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
>>> get_unique_path("image.png") # if exists
|
|
173
|
+
'image_1.png'
|
|
174
|
+
"""
|
|
175
|
+
if not os.path.exists(path):
|
|
176
|
+
return path
|
|
177
|
+
|
|
178
|
+
p = Path(path)
|
|
179
|
+
stem = p.stem
|
|
180
|
+
suffix = p.suffix
|
|
181
|
+
parent = p.parent
|
|
182
|
+
|
|
183
|
+
counter = 1
|
|
184
|
+
while True:
|
|
185
|
+
new_path = parent / f"{stem}_{counter}{suffix}"
|
|
186
|
+
if not os.path.exists(new_path):
|
|
187
|
+
return str(new_path)
|
|
188
|
+
counter += 1
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def ensure_extension(path: str, default_ext: str) -> str:
|
|
192
|
+
"""
|
|
193
|
+
Ensure a file path has an extension.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
path: File path
|
|
197
|
+
default_ext: Default extension to add if missing
|
|
198
|
+
|
|
199
|
+
Returns:
|
|
200
|
+
Path with extension
|
|
201
|
+
"""
|
|
202
|
+
p = Path(path)
|
|
203
|
+
if not p.suffix:
|
|
204
|
+
ext = default_ext if default_ext.startswith(".") else f".{default_ext}"
|
|
205
|
+
return str(p) + ext
|
|
206
|
+
return path
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_extension(path: str) -> str:
|
|
210
|
+
"""
|
|
211
|
+
Get the normalized extension from a file path.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
path: File path
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
Normalized extension without dot
|
|
218
|
+
"""
|
|
219
|
+
ext = Path(path).suffix
|
|
220
|
+
return normalize_ext(ext) if ext else ""
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def exts_from_filter(selected_filter: str) -> List[str]:
|
|
224
|
+
"""
|
|
225
|
+
Extract extensions from a Qt name filter string.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
selected_filter: Qt filter string like "TIFF (*.tif *.tiff)"
|
|
229
|
+
|
|
230
|
+
Returns:
|
|
231
|
+
List of normalized extensions
|
|
232
|
+
|
|
233
|
+
Example:
|
|
234
|
+
>>> exts_from_filter("TIFF (*.tif *.tiff)")
|
|
235
|
+
['tif']
|
|
236
|
+
"""
|
|
237
|
+
exts = [
|
|
238
|
+
m.group(1).lower()
|
|
239
|
+
for m in re.finditer(r"\*\.\s*([A-Za-z0-9]+)", selected_filter)
|
|
240
|
+
]
|
|
241
|
+
if not exts:
|
|
242
|
+
return []
|
|
243
|
+
|
|
244
|
+
# Normalize and uniquify while preserving order
|
|
245
|
+
seen: Set[str] = set()
|
|
246
|
+
out: List[str] = []
|
|
247
|
+
for e in exts:
|
|
248
|
+
n = normalize_ext(e)
|
|
249
|
+
if n not in seen:
|
|
250
|
+
seen.add(n)
|
|
251
|
+
out.append(n)
|
|
252
|
+
return out
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
# Alias for backward compatibility
|
|
256
|
+
_exts_from_filter = exts_from_filter
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
# ---------------------------------------------------------------------------
|
|
260
|
+
# Module exports
|
|
261
|
+
# ---------------------------------------------------------------------------
|
|
262
|
+
|
|
263
|
+
__all__ = [
|
|
264
|
+
# Constants
|
|
265
|
+
'REPLACE_SPACES_WITH_UNDERSCORES',
|
|
266
|
+
'WIN_RESERVED_NAMES',
|
|
267
|
+
'EXT_ALIASES',
|
|
268
|
+
'ALLOWED_BIT_DEPTHS',
|
|
269
|
+
|
|
270
|
+
# Extension normalization
|
|
271
|
+
'normalize_ext',
|
|
272
|
+
'_normalize_ext',
|
|
273
|
+
|
|
274
|
+
# Filename sanitization
|
|
275
|
+
'sanitize_filename',
|
|
276
|
+
'_sanitize_filename',
|
|
277
|
+
|
|
278
|
+
# Path utilities
|
|
279
|
+
'get_unique_path',
|
|
280
|
+
'ensure_extension',
|
|
281
|
+
'get_extension',
|
|
282
|
+
'exts_from_filter',
|
|
283
|
+
'_exts_from_filter',
|
|
284
|
+
]
|