astroimred 0.4.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. astroimred-0.4.0/.github/tests/test_release.py +122 -0
  2. astroimred-0.4.0/CHANGELOG.md +39 -0
  3. astroimred-0.4.0/LICENSE +28 -0
  4. astroimred-0.4.0/PKG-INFO +63 -0
  5. astroimred-0.4.0/README.md +14 -0
  6. astroimred-0.4.0/RELEASING.md +152 -0
  7. astroimred-0.4.0/pyproject.toml +117 -0
  8. astroimred-0.4.0/pyproject.toml.orig +105 -0
  9. astroimred-0.4.0/scripts/check_release.py +161 -0
  10. astroimred-0.4.0/scripts/smoke_install.py +56 -0
  11. astroimred-0.4.0/src/astroimred/__init__.py +18 -0
  12. astroimred-0.4.0/src/astroimred/_core/__init__.py +9 -0
  13. astroimred-0.4.0/src/astroimred/_core/astropy_helpers.py +299 -0
  14. astroimred-0.4.0/src/astroimred/_core/geometry.py +268 -0
  15. astroimred-0.4.0/src/astroimred/_core/numeric.py +531 -0
  16. astroimred-0.4.0/src/astroimred/_core/scales.py +61 -0
  17. astroimred-0.4.0/src/astroimred/_core/system.py +36 -0
  18. astroimred-0.4.0/src/astroimred/_core/types.py +30 -0
  19. astroimred-0.4.0/src/astroimred/_core/wcs.py +122 -0
  20. astroimred-0.4.0/src/astroimred/cli.py +44 -0
  21. astroimred-0.4.0/src/astroimred/external/__init__.py +7 -0
  22. astroimred-0.4.0/src/astroimred/external/sep.py +838 -0
  23. astroimred-0.4.0/src/astroimred/fitsmgmt/__init__.py +9 -0
  24. astroimred-0.4.0/src/astroimred/fitsmgmt/airmass.py +464 -0
  25. astroimred-0.4.0/src/astroimred/fitsmgmt/header.py +778 -0
  26. astroimred-0.4.0/src/astroimred/fitsmgmt/io.py +1029 -0
  27. astroimred-0.4.0/src/astroimred/fitsmgmt/naming.py +276 -0
  28. astroimred-0.4.0/src/astroimred/fitsmgmt/table.py +904 -0
  29. astroimred-0.4.0/src/astroimred/fitsmgmt/wcs.py +683 -0
  30. astroimred-0.4.0/src/astroimred/imutil/__init__.py +6 -0
  31. astroimred-0.4.0/src/astroimred/imutil/_docstrings.py +360 -0
  32. astroimred-0.4.0/src/astroimred/imutil/_util_fits.py +1372 -0
  33. astroimred-0.4.0/src/astroimred/imutil/ccdops.py +865 -0
  34. astroimred-0.4.0/src/astroimred/imutil/imarith.py +420 -0
  35. astroimred-0.4.0/src/astroimred/imutil/imcombine.py +1057 -0
  36. astroimred-0.4.0/src/astroimred/imutil/imcopy.py +160 -0
  37. astroimred-0.4.0/src/astroimred/imutil/imsmooth.py +45 -0
  38. astroimred-0.4.0/src/astroimred/imutil/imstat.py +322 -0
  39. astroimred-0.4.0/src/astroimred/imutil/pixels.py +456 -0
  40. astroimred-0.4.0/src/astroimred/logging.py +35 -0
  41. astroimred-0.4.0/src/astroimred/phot/__init__.py +14 -0
  42. astroimred-0.4.0/src/astroimred/phot/aperture.py +159 -0
  43. astroimred-0.4.0/src/astroimred/phot/apphot.py +549 -0
  44. astroimred-0.4.0/src/astroimred/phot/background.py +565 -0
  45. astroimred-0.4.0/src/astroimred/phot/center.py +1277 -0
  46. astroimred-0.4.0/src/astroimred/phot/daopsf.py +479 -0
  47. astroimred-0.4.0/src/astroimred/phot/growth.py +164 -0
  48. astroimred-0.4.0/src/astroimred/phot/polarimetry.py +1006 -0
  49. astroimred-0.4.0/src/astroimred/phot/radprof.py +480 -0
  50. astroimred-0.4.0/src/astroimred/reduction/__init__.py +3 -0
  51. astroimred-0.4.0/src/astroimred/reduction/_presets.py +74 -0
  52. astroimred-0.4.0/src/astroimred/reduction/cli.py +744 -0
  53. astroimred-0.4.0/src/astroimred/reduction/crrej.py +898 -0
  54. astroimred-0.4.0/src/astroimred/reduction/preproc.py +1011 -0
  55. astroimred-0.4.0/src/astroimred/viz/__init__.py +4 -0
  56. astroimred-0.4.0/src/astroimred/viz/imshow.py +251 -0
  57. astroimred-0.4.0/src/astroimred/viz/ticks.py +77 -0
  58. astroimred-0.4.0/tests/conftest.py +85 -0
  59. astroimred-0.4.0/tests/fitsmgmt/__init__.py +1 -0
  60. astroimred-0.4.0/tests/fitsmgmt/test_airmass.py +131 -0
  61. astroimred-0.4.0/tests/fitsmgmt/test_headers.py +104 -0
  62. astroimred-0.4.0/tests/fitsmgmt/test_io.py +253 -0
  63. astroimred-0.4.0/tests/fitsmgmt/test_summary.py +139 -0
  64. astroimred-0.4.0/tests/fitsmgmt/test_summary_export.py +109 -0
  65. astroimred-0.4.0/tests/fitsmgmt/test_wcstools.py +91 -0
  66. astroimred-0.4.0/tests/imutil/__init__.py +1 -0
  67. astroimred-0.4.0/tests/imutil/test_ccdops.py +172 -0
  68. astroimred-0.4.0/tests/imutil/test_chunked_fits_io.py +431 -0
  69. astroimred-0.4.0/tests/imutil/test_imstat.py +234 -0
  70. astroimred-0.4.0/tests/imutil/test_pixels.py +105 -0
  71. astroimred-0.4.0/tests/imutil/test_rejection_diagnostics.py +368 -0
  72. astroimred-0.4.0/tests/imutil/test_stack_memory.py +190 -0
  73. astroimred-0.4.0/tests/imutil/test_weighted_combine.py +183 -0
  74. astroimred-0.4.0/tests/phot/__init__.py +30 -0
  75. astroimred-0.4.0/tests/phot/conftest.py +325 -0
  76. astroimred-0.4.0/tests/phot/test_aperture.py +178 -0
  77. astroimred-0.4.0/tests/phot/test_apphot.py +463 -0
  78. astroimred-0.4.0/tests/phot/test_astroapers_parity.py +322 -0
  79. astroimred-0.4.0/tests/phot/test_background.py +673 -0
  80. astroimred-0.4.0/tests/phot/test_center.py +538 -0
  81. astroimred-0.4.0/tests/phot/test_polarimetry.py +634 -0
  82. astroimred-0.4.0/tests/phot/test_radprof.py +475 -0
  83. astroimred-0.4.0/tests/phot/test_seputil.py +577 -0
  84. astroimred-0.4.0/tests/phot/test_util.py +416 -0
  85. astroimred-0.4.0/tests/reduction/__init__.py +1 -0
  86. astroimred-0.4.0/tests/reduction/conftest.py +4 -0
  87. astroimred-0.4.0/tests/reduction/test_cli.py +214 -0
  88. astroimred-0.4.0/tests/reduction/test_crrej.py +111 -0
  89. astroimred-0.4.0/tests/reduction/test_imarith.py +61 -0
  90. astroimred-0.4.0/tests/reduction/test_imcombine.py +697 -0
  91. astroimred-0.4.0/tests/reduction/test_preproc.py +228 -0
  92. astroimred-0.4.0/tests/test_astroimred.py +224 -0
  93. astroimred-0.4.0/tests/test_core_helpers.py +85 -0
  94. astroimred-0.4.0/tests/test_core_numeric.py +614 -0
  95. astroimred-0.4.0/tests/verify_astroimred.py +191 -0
  96. astroimred-0.4.0/tests/viz/test_imshow.py +73 -0
@@ -0,0 +1,122 @@
1
+ """Test release rejection paths without importing astroimred or its dependencies."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import importlib.util
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+ import pytest
10
+
11
+ _ROOT = Path(__file__).resolve().parents[2]
12
+ _SPEC = importlib.util.spec_from_file_location(
13
+ "check_release", _ROOT / "scripts/check_release.py"
14
+ )
15
+ assert _SPEC is not None and _SPEC.loader is not None
16
+ release = importlib.util.module_from_spec(_SPEC)
17
+ _SPEC.loader.exec_module(release)
18
+
19
+
20
+ @pytest.fixture
21
+ def project(tmp_path: Path) -> Path:
22
+ """Create a minimal, valid release tree."""
23
+ (tmp_path / "pyproject.toml").write_text(
24
+ '[project]\nname = "astroimred"\nversion = "1.2.3"\n'
25
+ 'dependencies = ["numpy>=1.24"]\n'
26
+ '[build-system]\nrequires = ["uv_build>=0.9.18,<0.10.0"]\n',
27
+ encoding="utf-8",
28
+ )
29
+ (tmp_path / "CHANGELOG.md").write_text(
30
+ "# Changelog\n\n## 1.2.3 - 2026-09-07\n\n- Release change.\n"
31
+ "\n## 1.2.2 - 2026-09-01\n\n- Older change.\n",
32
+ encoding="utf-8",
33
+ )
34
+ return tmp_path
35
+
36
+
37
+ def test_release_extracts_only_matching_notes(project: Path) -> None:
38
+ assert release.check_release(project, tag="v1.2.3") == (
39
+ "1.2.3",
40
+ "- Release change.\n",
41
+ )
42
+
43
+
44
+ def test_rehearsal_accepts_pending_changes(project: Path) -> None:
45
+ (project / "CHANGELOG.md").write_text(
46
+ "## Unreleased\n\n- Pending.\n", encoding="utf-8"
47
+ )
48
+ assert release.check_release(project) == ("1.2.3", "- Pending.\n")
49
+
50
+
51
+ @pytest.mark.parametrize("tag", ["v1.2.4", "1.2.3", "v1.2.3rc1", "v01.2.3", ""])
52
+ def test_rejects_wrong_tags(project: Path, tag: str) -> None:
53
+ with pytest.raises(ValueError, match="tag"):
54
+ release.check_release(project, tag=tag)
55
+
56
+
57
+ @pytest.mark.parametrize("version", ["1.2.3rc1", "01.2.3", "1.2", "1.2.3+local"])
58
+ def test_rejects_nonstable_versions(project: Path, version: str) -> None:
59
+ manifest = project / "pyproject.toml"
60
+ manifest.write_text(
61
+ manifest.read_text().replace('"1.2.3"', f'"{version}"'), encoding="utf-8"
62
+ )
63
+ with pytest.raises(ValueError, match="stable"):
64
+ release.check_release(project)
65
+
66
+
67
+ @pytest.mark.parametrize(
68
+ "notes",
69
+ [
70
+ "## Unreleased\n\n- Pending.\n\n## 1.2.3 - 2026-09-07\n\n- Change.\n",
71
+ "## 1.2.3 - 2026-09-07\n",
72
+ "## 1.2.3 - 2026-09-07\n\n### Added\n",
73
+ "## 1.2.3 - 2026-02-30\n\n- Change.\n",
74
+ "## 1.2.3 - soon\n\n- Change.\n",
75
+ "## 1.2.2 - 2026-09-07\n\n- Change.\n",
76
+ "## 1.2.3 - 2026-09-07\n\n- A.\n\n## 1.2.3 - 2026-09-08\n\n- B.\n",
77
+ "## Unreleased\n\n## Unreleased\n",
78
+ ],
79
+ )
80
+ def test_rejects_unready_release_notes(project: Path, notes: str) -> None:
81
+ (project / "CHANGELOG.md").write_text(notes, encoding="utf-8")
82
+ with pytest.raises(ValueError):
83
+ release.check_release(project, tag="v1.2.3")
84
+
85
+
86
+ def test_rejects_direct_dependencies(project: Path) -> None:
87
+ manifest = project / "pyproject.toml"
88
+ manifest.write_text(
89
+ manifest.read_text().replace("numpy>=1.24", "numpy @ file:///sibling/numpy"),
90
+ encoding="utf-8",
91
+ )
92
+ with pytest.raises(ValueError, match="registry"):
93
+ release.check_release(project)
94
+
95
+
96
+ def test_clean_check_detects_untracked_files(project: Path) -> None:
97
+ subprocess.run(["git", "init", "--quiet", str(project)], check=True)
98
+ with pytest.raises(ValueError, match="pending changes"):
99
+ release.check_release(project, require_clean=True)
100
+
101
+
102
+ def test_cli_outputs_and_failure(project: Path, tmp_path: Path) -> None:
103
+ output = tmp_path / "output"
104
+ notes = tmp_path / "notes"
105
+ assert (
106
+ release.main(
107
+ [
108
+ "--root",
109
+ str(project),
110
+ "--tag",
111
+ "v1.2.3",
112
+ "--github-output",
113
+ str(output),
114
+ "--notes-output",
115
+ str(notes),
116
+ ]
117
+ )
118
+ == 0
119
+ )
120
+ assert output.read_text() == "version=1.2.3\n"
121
+ assert notes.read_text() == "- Release change.\n"
122
+ assert release.main(["--root", str(project), "--tag", "v9.0.0"]) == 1
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ ## 0.4.0 - 2026-11-12
4
+
5
+ ### Breaking changes
6
+
7
+ - Aperture-sum errors used `sqrt(sum(w * error**2))` and overestimated small
8
+ apertures; `apsum_err` and `radcum_profile` errors now use
9
+ `sqrt(sum(w**2 * error**2))` (`w`: pixel-overlap weight), as photutils 3.1 does.
10
+ - `srcsum_err` counted sky noise twice and omitted the sky-estimate error; it
11
+ now uses `sqrt(apsum_err**2 + (apsum_npix * dsky)**2)`.
12
+ - `sky_fit` and `apphot_annulus` add `dsky`, the standard error of `msky`
13
+ (`radial_profile`: `dpix`).
14
+
15
+ ## 0.3.0 - 2026-06-18
16
+
17
+ - Migrated aperture photometry and image combination to the `astroapers` and `imcombiners` backends; deprecated `combutil`.
18
+ - Added linear WCS helper functions (`local_cd_matrix`, `make_linear_wcs`, `make_zoomed_wcs`).
19
+ - Performance improvements: cached regex, `fitsio`-preferred I/O, and perf for `bin_ccd` and `sep`-based extraction.
20
+ - Unified logging across the package.
21
+ - Large-scale internal reorganization and type-hint cleanup.
22
+ - [breaking] Removed FWHM-based aperture initialization.
23
+
24
+ ## 0.2.0 - 2026-05-07
25
+
26
+ - Bumped to v0.2.0.
27
+ - Python >=3.11 and Astropy >=7.0. Some type hints and Astropy-affiliated dependency floors were updated accordingly.
28
+ - Renamed `make_summary` to `fits_summary` and added `.parq`/`.parquet` summary output.
29
+
30
+ ## 0.1.1 - 2026-05-07
31
+
32
+ - Bumped to v0.1.1.
33
+ - Fixed minor typos in comments and docstrings.
34
+ - Replaced diagnostic `print` calls and non-deprecation warnings with package logger calls.
35
+ - Added small neutral type hints and formatting/import cleanup.
36
+
37
+ ## 0.1.0 - 2026-05-07
38
+
39
+ - Initial port of FITS management utilities from `ysfitsutilpy` and lightweight visualization helpers from `ysvisutilpy`.
@@ -0,0 +1,28 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, Yoonsoo P. Bach
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+
11
+ 2. Redistributions in binary form must reproduce the above copyright notice,
12
+ this list of conditions and the following disclaimer in the documentation
13
+ and/or other materials provided with the distribution.
14
+
15
+ 3. Neither the name of the copyright holder nor the names of its
16
+ contributors may be used to endorse or promote products derived from
17
+ this software without specific prior written permission.
18
+
19
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,63 @@
1
+ Metadata-Version: 2.4
2
+ Name: astroimred
3
+ Version: 0.4.0
4
+ Summary: FITS file management and lightweight inspection utilities.
5
+ Author: ysBach
6
+ Author-email: ysBach <ysbach93@gmail.com>
7
+ License-Expression: BSD-3-Clause
8
+ License-File: LICENSE
9
+ Requires-Dist: astropy>=7.0
10
+ Requires-Dist: astro-ndslice>=0.2
11
+ Requires-Dist: numpy>=1.24
12
+ Requires-Dist: pandas>=2.0
13
+ Requires-Dist: pyarrow>=14
14
+ Requires-Dist: astroapers>=0.1.2
15
+ Requires-Dist: imcombiners>=0.1.1
16
+ Requires-Dist: reducers>=0.3.0
17
+ Requires-Dist: astroapers ; extra == 'full'
18
+ Requires-Dist: fitsio>=1.2 ; extra == 'full'
19
+ Requires-Dist: astroscrappy>=1.1 ; extra == 'full'
20
+ Requires-Dist: ccdproc>=2.0 ; extra == 'full'
21
+ Requires-Dist: click>=8.0 ; extra == 'full'
22
+ Requires-Dist: fitsio>=1.2 ; extra == 'full'
23
+ Requires-Dist: matplotlib>=3.9.1 ; extra == 'full'
24
+ Requires-Dist: numba>=0.59 ; extra == 'full'
25
+ Requires-Dist: numexpr>=2.8 ; extra == 'full'
26
+ Requires-Dist: photutils>=2.0,<4.0 ; extra == 'full'
27
+ Requires-Dist: pyarrow>=14 ; extra == 'full'
28
+ Requires-Dist: scipy>=1.9.2 ; extra == 'full'
29
+ Requires-Dist: sep>=1.4 ; extra == 'full'
30
+ Requires-Dist: astroapers ; extra == 'phot'
31
+ Requires-Dist: matplotlib>=3.9.1 ; extra == 'phot'
32
+ Requires-Dist: photutils>=2.0,<4.0 ; extra == 'phot'
33
+ Requires-Dist: scipy>=1.9.2 ; extra == 'phot'
34
+ Requires-Dist: sep>=1.4 ; extra == 'phot'
35
+ Requires-Dist: astroscrappy>=1.1 ; extra == 'reduction'
36
+ Requires-Dist: ccdproc>=2.0 ; extra == 'reduction'
37
+ Requires-Dist: click>=8.0 ; extra == 'reduction'
38
+ Requires-Dist: numba>=0.59 ; extra == 'reduction'
39
+ Requires-Dist: scipy>=1.9.2 ; extra == 'reduction'
40
+ Requires-Python: >=3.11
41
+ Project-URL: Documentation, https://ysbach.github.io/astroimred/
42
+ Project-URL: Repository, https://github.com/ysBach/astroimred
43
+ Project-URL: Issues, https://github.com/ysBach/astroimred/issues
44
+ Project-URL: Changelog, https://github.com/ysBach/astroimred/blob/main/CHANGELOG.md
45
+ Provides-Extra: full
46
+ Provides-Extra: phot
47
+ Provides-Extra: reduction
48
+ Description-Content-Type: text/markdown
49
+
50
+ # astroimred
51
+
52
+ [FITS](https://en.wikipedia.org/wiki/FITS) file management and manipulation tool.
53
+
54
+ Recommended import:
55
+
56
+ ```python
57
+ import astroimred as air
58
+ ```
59
+
60
+ Many of initial skeleton are directly borrowed from legacy FITS utilities.
61
+
62
+ Reduction utilities from the former `fitsimred` package are being ported into
63
+ the `astroimred.reduction` namespace.
@@ -0,0 +1,14 @@
1
+ # astroimred
2
+
3
+ [FITS](https://en.wikipedia.org/wiki/FITS) file management and manipulation tool.
4
+
5
+ Recommended import:
6
+
7
+ ```python
8
+ import astroimred as air
9
+ ```
10
+
11
+ Many of initial skeleton are directly borrowed from legacy FITS utilities.
12
+
13
+ Reduction utilities from the former `fitsimred` package are being ported into
14
+ the `astroimred.reduction` namespace.
@@ -0,0 +1,152 @@
1
+ # Release astroimred
2
+
3
+ **Run a manual rehearsal, then push the matching `vX.Y.Z` tag to publish.**
4
+ Use the exact commit that passed the rehearsal.
5
+
6
+ | Event | Checks | Publication |
7
+ | --- | --- | --- |
8
+ | Branch push or pull request | CI and installed distributions | None |
9
+ | Manual `release.yml` | Same checks; dated notes required when run on a tag | None |
10
+ | Matching `vX.Y.Z` tag push | Same checks, plus dated release notes | PyPI, then GitHub release |
11
+
12
+ ## Shared convention
13
+
14
+ Keep publication in one `release.yml`. The convention combines ImCombiners'
15
+ tag trigger, reducers' reusable CI and early release-note checks, and pqfilt's
16
+ installed-artifact checks. A GitHub release records successful publication;
17
+ creating one does not trigger publishing.
18
+
19
+ | Package type | Artifacts | Registries |
20
+ | --- | --- | --- |
21
+ | `astroimred`: pure Python, `uv_build` | One universal wheel and sdist | PyPI |
22
+ | `astroapers`: Maturin, public Rust API | Per-Python/platform wheels and sdist | PyPI and crates.io |
23
+
24
+ Publish the exact Python files that passed installation tests. Rust publication
25
+ packages the checked commit again with Cargo. Use registry dependencies and
26
+ temporary OIDC credentials. Never synchronize `~/.venvs/ysbpy`.
27
+
28
+ ## One-time setup
29
+
30
+ 1. Confirm the GitHub repository is `ysBach/astroimred`. Older clones can retain
31
+ the former `fitsmgmt` remote; inspect `git remote -v` and update it if needed:
32
+
33
+ ```sh
34
+ git remote set-url origin https://github.com/ysBach/astroimred.git
35
+ ```
36
+
37
+ The publisher job permits only `ysBach/astroimred`. A repository rename also
38
+ requires changing that guard and the PyPI trusted-publisher settings.
39
+
40
+ 2. Create a GitHub environment named `pypi`. Restrict deployment to **tags**
41
+ matching `v*`. For fully automatic releases after tagging, do not configure
42
+ required environment reviewers. Protect tag creation with a repository ruleset.
43
+
44
+ 3. Add a trusted publisher in
45
+ [PyPI Publishing settings](https://pypi.org/manage/project/astroimred/settings/publishing/):
46
+
47
+ | Setting | Value |
48
+ | --- | --- |
49
+ | Project | `astroimred` |
50
+ | Owner / repository | `ysBach` / `astroimred` |
51
+ | Workflow filename | `release.yml` |
52
+ | Environment | `pypi` |
53
+
54
+ For a project that does not exist yet, use a
55
+ [pending publisher](https://docs.pypi.org/trusted-publishers/creating-a-project-through-oidc/).
56
+ No permanent PyPI token belongs in GitHub secrets.
57
+
58
+ 4. Enable Actions and require the CI build and installed-distribution checks
59
+ on `main`. Select their actual check names after the first hosted run.
60
+ Repository and registry settings are external setup; committing these files
61
+ does not configure them.
62
+
63
+ ## Prepare and rehearse
64
+
65
+ 1. Select the next unused version in `pyproject.toml`. Move `Unreleased` notes
66
+ into one nonempty `## X.Y.Z - YYYY-MM-DD` section with the real release date.
67
+ Leave `Unreleased` empty or remove it. The checker rejects prerelease tags,
68
+ mismatches, duplicate sections, and pending notes on tagged releases.
69
+
70
+ 2. Activate the shared environment for local release-tool checks:
71
+
72
+ ```sh
73
+ source ~/.venvs/ysbpy/bin/activate
74
+ uv run --active --no-sync python scripts/check_release.py
75
+ uv run --active --no-sync pytest .github/tests -q
76
+ ```
77
+
78
+ Release tooling requires Python 3.11+. With a project `.venv`, omit `--active`.
79
+ Do not run `uv sync` or `uv pip sync` against the shared environment.
80
+ `uv.lock` is intentionally untracked here: the version comes from
81
+ `pyproject.toml`, and CI resolves published dependencies for fresh installs.
82
+
83
+ 3. Review and commit the intended files, including new files. Push the commit
84
+ and start a rehearsal:
85
+
86
+ ```sh
87
+ uv run --active --no-sync python scripts/check_release.py --require-clean
88
+ git push origin main
89
+ gh workflow run release.yml --ref main
90
+ gh run list --workflow release.yml
91
+ ```
92
+
93
+ 4. Inspect the run with `gh run view RUN_ID`. All checks must pass; PyPI and
94
+ GitHub release jobs must be skipped. Record the successful run's full commit
95
+ SHA with `gh run view RUN_ID --json headSha --jq .headSha`.
96
+
97
+ ## Publish
98
+
99
+ 1. Check out that exact commit. Replace `REHEARSED_COMMIT_SHA` and `X.Y.Z`:
100
+
101
+ ```sh
102
+ git switch --detach REHEARSED_COMMIT_SHA
103
+ uv run --active --no-sync python scripts/check_release.py --tag vX.Y.Z --require-clean
104
+ git tag -a vX.Y.Z -m "Release X.Y.Z"
105
+ git push origin vX.Y.Z
106
+ git switch main
107
+ ```
108
+
109
+ **Pushing the tag publishes automatically.** A version bump or ordinary push
110
+ does not publish. Versions are selected by the maintainer, not by CI.
111
+
112
+ 2. Check the tag-triggered Actions run, the PyPI version page, and the GitHub
113
+ release. Its wheel, sdist, and notes come from the same successful run.
114
+
115
+ ## Coverage and recovery
116
+
117
+ ### Check the tested artifacts
118
+
119
+ CI builds a `py3-none-any` wheel and sdist.
120
+
121
+ | Platform | Python coverage |
122
+ | --- | --- |
123
+ | Linux | 3.11–3.14; also installs the sdist on 3.14 |
124
+ | macOS ARM64 | 3.13 |
125
+ | Windows x86-64 | 3.13 |
126
+
127
+ Each install uses the `full` extra in a fresh environment. Checks cover isolated
128
+ imports, license/FITS handling, CLI help, and the Python suite. Release-tool
129
+ tests and Ruff checks cover `scripts/` and `.github/tests/`; existing application
130
+ formatting is outside this publishing change. These are configured targets,
131
+ not evidence of compatibility until hosted runs pass.
132
+
133
+ `UV_NO_SOURCES=true` disables developer overrides. Dependencies must be available
134
+ from registries; a test that needs unpublished sibling changes must fail until
135
+ those dependencies are released. CI intentionally does not substitute sibling
136
+ checkouts. The same retained wheel and sdist are uploaded without rebuilding.
137
+
138
+ ### Recover without changing published files
139
+
140
+ - **Before uploading:** fix the problem, commit, and rehearse again. Source or
141
+ artifact changes after a tag push require a new version/tag; never move a
142
+ published tag.
143
+ - **Upload/network/setup failure:** fix the external issue and rerun only failed
144
+ jobs in the original tag-push run. Keep its original artifacts. `uv publish`
145
+ skips identical existing files and rejects conflicting bytes; see
146
+ [uv retry behavior](https://docs.astral.sh/uv/guides/package/).
147
+ - **GitHub release failure after PyPI succeeded:** rerun the failed job if no
148
+ GitHub release exists. If one exists, inspect it and restore missing assets
149
+ from the original run. Do not rebuild files or republish changed bytes.
150
+
151
+ PyPI publication and GitHub release creation are separate operations; a partial
152
+ release is possible. Retain the original successful artifacts during recovery.
@@ -0,0 +1,117 @@
1
+ [project]
2
+ name = "astroimred"
3
+ version = "0.4.0"
4
+ description = "FITS file management and lightweight inspection utilities."
5
+ readme = "README.md"
6
+ license = "BSD-3-Clause"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.11"
9
+ dependencies = [
10
+ "astropy>=7.0",
11
+ "astro-ndslice>=0.2",
12
+ "numpy>=1.24",
13
+ "pandas>=2.0",
14
+ "pyarrow>=14",
15
+ "astroapers>=0.1.2",
16
+ "imcombiners>=0.1.1",
17
+ "reducers>=0.3.0",
18
+ ]
19
+
20
+ [[project.authors]]
21
+ name = "ysBach"
22
+ email = "ysbach93@gmail.com"
23
+
24
+ [project.scripts]
25
+ imred = "astroimred.reduction.cli:main"
26
+
27
+ [project.urls]
28
+ Documentation = "https://ysbach.github.io/astroimred/"
29
+ Repository = "https://github.com/ysBach/astroimred"
30
+ Issues = "https://github.com/ysBach/astroimred/issues"
31
+ Changelog = "https://github.com/ysBach/astroimred/blob/main/CHANGELOG.md"
32
+
33
+ [project.optional-dependencies]
34
+ phot = [
35
+ "astroapers",
36
+ "matplotlib>=3.9.1",
37
+ "photutils>=2.0,<4.0",
38
+ "scipy>=1.9.2",
39
+ "sep>=1.4",
40
+ ]
41
+ reduction = [
42
+ "astroscrappy>=1.1",
43
+ "ccdproc>=2.0",
44
+ "click>=8.0",
45
+ "numba>=0.59",
46
+ "scipy>=1.9.2",
47
+ ]
48
+ full = [
49
+ "astroapers",
50
+ "fitsio>=1.2",
51
+ "astroscrappy>=1.1",
52
+ "ccdproc>=2.0",
53
+ "click>=8.0",
54
+ "fitsio>=1.2",
55
+ "matplotlib>=3.9.1",
56
+ "numba>=0.59",
57
+ "numexpr>=2.8",
58
+ "photutils>=2.0,<4.0",
59
+ "pyarrow>=14",
60
+ "scipy>=1.9.2",
61
+ "sep>=1.4",
62
+ ]
63
+
64
+ [dependency-groups]
65
+ dev = [
66
+ "pytest>=8.0",
67
+ "ruff>=0.8",
68
+ "sphinx>=7.2",
69
+ "sphinx-rtd-theme>=2.0",
70
+ ]
71
+
72
+ [tool.ruff]
73
+ line-length = 88
74
+ target-version = "py311"
75
+ src = [
76
+ "src",
77
+ "tests",
78
+ ]
79
+
80
+ [tool.ruff.lint]
81
+ select = [
82
+ "E",
83
+ "F",
84
+ "W",
85
+ "I",
86
+ "UP",
87
+ "B",
88
+ "C4",
89
+ "SIM",
90
+ ]
91
+ ignore = [
92
+ "E501",
93
+ "W605",
94
+ ]
95
+ fixable = ["ALL"]
96
+
97
+ [tool.ruff.lint.per-file-ignores]
98
+ "src/astroimred/**/__init__.py" = [
99
+ "F401",
100
+ "F403",
101
+ ]
102
+
103
+ [tool.ruff.format]
104
+ line-ending = "auto"
105
+
106
+ [tool.uv.build-backend]
107
+ source-include = [
108
+ "CHANGELOG.md",
109
+ "RELEASING.md",
110
+ "scripts/**",
111
+ ".github/tests/**",
112
+ "tests/**",
113
+ ]
114
+
115
+ [build-system]
116
+ requires = ["uv_build>=0.9.18,<0.10.0"]
117
+ build-backend = "uv_build"
@@ -0,0 +1,105 @@
1
+ [project]
2
+ name = "astroimred"
3
+ version = "0.4.0"
4
+ description = "FITS file management and lightweight inspection utilities."
5
+ readme = "README.md"
6
+ license = "BSD-3-Clause"
7
+ license-files = ["LICENSE"]
8
+ authors = [
9
+ { name = "ysBach", email = "ysbach93@gmail.com" }
10
+ ]
11
+ requires-python = ">=3.11"
12
+ # Core dependencies for basic manipulation of FITS
13
+ dependencies = [
14
+ "astropy>=7.0",
15
+ "astro-ndslice>=0.2",
16
+ "numpy>=1.24",
17
+ "pandas>=2.0",
18
+ "pyarrow>=14",
19
+ "astroapers>=0.1.2",
20
+ "imcombiners>=0.1.1",
21
+ "reducers>=0.3.0",
22
+ ]
23
+
24
+ [project.scripts]
25
+ imred = "astroimred.reduction.cli:main"
26
+
27
+ [project.urls]
28
+ Documentation = "https://ysbach.github.io/astroimred/"
29
+ Repository = "https://github.com/ysBach/astroimred"
30
+ Issues = "https://github.com/ysBach/astroimred/issues"
31
+ Changelog = "https://github.com/ysBach/astroimred/blob/main/CHANGELOG.md"
32
+
33
+ [project.optional-dependencies]
34
+ phot = [
35
+ "astroapers",
36
+ "matplotlib>=3.9.1",
37
+ "photutils>=2.0,<4.0",
38
+ "scipy>=1.9.2",
39
+ "sep>=1.4",
40
+ ]
41
+ reduction = [
42
+ "astroscrappy>=1.1",
43
+ "ccdproc>=2.0",
44
+ "click>=8.0",
45
+ "numba>=0.59",
46
+ "scipy>=1.9.2",
47
+ ]
48
+ full = [
49
+ "astroapers",
50
+ "fitsio>=1.2",
51
+ "astroscrappy>=1.1",
52
+ "ccdproc>=2.0",
53
+ "click>=8.0",
54
+ "fitsio>=1.2",
55
+ "matplotlib>=3.9.1",
56
+ "numba>=0.59",
57
+ "numexpr>=2.8",
58
+ "photutils>=2.0,<4.0",
59
+ "pyarrow>=14",
60
+ "scipy>=1.9.2",
61
+ "sep>=1.4",
62
+ ]
63
+
64
+ [dependency-groups]
65
+ dev = [
66
+ "pytest>=8.0",
67
+ "ruff>=0.8",
68
+ "sphinx>=7.2",
69
+ "sphinx-rtd-theme>=2.0",
70
+ ]
71
+
72
+ [tool.ruff]
73
+ line-length = 88
74
+ target-version = "py311"
75
+ src = ["src", "tests"]
76
+
77
+ [tool.ruff.lint]
78
+ select = [
79
+ "E", # pycodestyle errors
80
+ "F", # Pyflakes
81
+ "W", # pycodestyle warnings
82
+ "I", # import sorting
83
+ "UP", # pyupgrade
84
+ "B", # flake8-bugbear
85
+ "C4", # comprehensions
86
+ "SIM", # simplifications
87
+ ]
88
+ ignore = [
89
+ "E501", # Let the formatter wrap what it can; tolerate intentional long lines.
90
+ "W605", # Legacy astronomy strings often contain backslash-style notation.
91
+ ]
92
+ fixable = ["ALL"]
93
+
94
+ [tool.ruff.lint.per-file-ignores]
95
+ "src/astroimred/**/__init__.py" = ["F401", "F403"]
96
+
97
+ [tool.ruff.format]
98
+ line-ending = "auto"
99
+
100
+ [build-system]
101
+ requires = ["uv_build>=0.9.18,<0.10.0"]
102
+ build-backend = "uv_build"
103
+
104
+ [tool.uv.build-backend]
105
+ source-include = ["CHANGELOG.md", "RELEASING.md", "scripts/**", ".github/tests/**", "tests/**"]