From 094a02c8762adc2ebd2db905424f9affe165b402 Mon Sep 17 00:00:00 2001 From: Hannu Parviainen Date: Sun, 1 Feb 2026 20:01:14 +0000 Subject: [PATCH 1/4] Dropped `specreduce.compat` and updated all references to use `specutils.Spectrum`. Bumped `specutils` minimum version to 2.0 and removed compatibility checks for older versions. --- docs/conf.py | 1 - docs/specphot_standards.rst | 4 ++-- docs/terms.rst | 14 +++++++------- pyproject.toml | 3 +-- specreduce/background.py | 23 +++++------------------ specreduce/calibration_data.py | 2 +- specreduce/compat.py | 11 ----------- specreduce/conftest.py | 15 +++------------ specreduce/core.py | 10 +++------- specreduce/extract.py | 6 +++--- specreduce/fluxcal.py | 2 +- specreduce/line_matching.py | 2 +- specreduce/tests/test_background.py | 2 +- specreduce/tests/test_extract.py | 2 +- specreduce/tests/test_image_parsing.py | 2 +- specreduce/tests/test_line_matching.py | 2 +- specreduce/tests/test_utils.py | 8 ++------ specreduce/tests/test_wavecal1d.py | 2 +- specreduce/tests/test_wavesol1d.py | 2 +- specreduce/wavecal1d.py | 2 +- specreduce/wavelength_calibration.py | 4 ++-- specreduce/wavesol1d.py | 2 +- tox.ini | 2 +- 23 files changed, 40 insertions(+), 83 deletions(-) delete mode 100644 specreduce/compat.py diff --git a/docs/conf.py b/docs/conf.py index 970944d3..1e62bc84 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -208,7 +208,6 @@ nitpick_ignore = [ ("py:class", "ArrayLike"), ("py:class", "numpy._typing.ArrayLike"), - ("py:class", "specutils.spectra.spectrum1d.Spectrum1D"), ] # Ignore complex type annotations that can't be cross-referenced diff --git a/docs/specphot_standards.rst b/docs/specphot_standards.rst index 869f8c2a..617f5a64 100644 --- a/docs/specphot_standards.rst +++ b/docs/specphot_standards.rst @@ -8,7 +8,7 @@ Introduction Instrument sensitivity as a function of wavelength is calibrated using observations of spectrophotometric standard stars. `specreduce `_ offers some -convenience functions for accessing some databases of commonly used standard stars and loading the data into `~specutils.Spectrum1D` +convenience functions for accessing some databases of commonly used standard stars and loading the data into `~specutils.Spectrum` instances. Supported Databases @@ -43,7 +43,7 @@ The bulk of them are inherited from IRAF's `onedstds `_, the `Nearby Supernova Factory `_, and `Gemini `_ are included as well. The -`~specreduce.calibration_data.load_onedstds` function is provided to load these data into `~specutils.Spectrum1D` +`~specreduce.calibration_data.load_onedstds` function is provided to load these data into `~specutils.Spectrum` instances. If `specreduce_data `_ is not installed, the data will be downloaded from the GitHub `repository `_. The available database names and their descriptions are listed here. Please refer to the `specreduce-data repository diff --git a/docs/terms.rst b/docs/terms.rst index 304bdfac..66f35bf7 100644 --- a/docs/terms.rst +++ b/docs/terms.rst @@ -65,7 +65,7 @@ Extraction ========== - The process of converting raw spectrum data on 2D image into flux versus - spectral axis or pixel (i.e. Spectrum1D), not necessarily flux or spectral + spectral axis or pixel (i.e. Spectrum), not necessarily flux or spectral calibration. Rectified ND spectrum @@ -227,8 +227,8 @@ MOS (Multi-Object Spectroscopy) - Also used as a shorthand for “the not spectral unit part of a 1D spectrum” (would that be the “dependent variable”?) - Oftentimes used to mean “flux density” -- `Spectrum1D - `__ +- `Spectrum + `__ uses the attribute 'flux'. Should this be renamed to 'flux_density'? - The intent in specutils was to not agonize over this but just accept that @@ -246,7 +246,7 @@ Flux Density - Collection of 1D spectra in a 2D array (image?), one spectrum per row. - Shared spectral axis. -- This is the format of specutils.Spectrum1D when it's a “vector” spectrum1D +- This is the format of specutils.Spectrum when it's a “vector” spectrum1D *Data cube* =========== @@ -280,12 +280,12 @@ Data Structures - Python Data structures, which are Python classes. - - NDData/NDCube/SpectrumCollection, Spectrum1D etc. + - NDData/NDCube/SpectrumCollection, Spectrum etc. - CCDData. Subclass of NDData - AstroData - from DRAGONS (collection of NDData-like objects, mapped to a file, plus metadata abstraction etc.) - Lots of classes to represent spectra - - Link to issue about renaming Spectrum1D class in specutils. + - Link to issue about renaming Spectrum class in specutils. - arrays *Data Model* @@ -439,7 +439,7 @@ API *Spectral class* ================ -- E.g., Spectrum1D +- E.g., Spectrum - In SDSS, 'class' is short for 'classification'. - DESI uses SPECTYPE for spectral type (QSO, GALAXY, STAR) diff --git a/pyproject.toml b/pyproject.toml index cb81d088..455a443c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ dependencies = [ "numpy>=1.24", "astropy>=5.3", "scipy>=1.10", - "specutils>=1.9.1", + "specutils>=2.0", "matplotlib>=3.10", "gwcs", ] @@ -89,7 +89,6 @@ filterwarnings = [ "ignore:.*utcfromtimestamp:DeprecationWarning", # DeprecationWarning from gwcs 0.18.3 in oldestdeps "ignore:.*pkg_resources.*:DeprecationWarning", - "ignore:The Spectrum1D class is deprecated and may be removed", # DeprecationWarning from gwcs in devdeps "ignore:The isiterable function is deprecated and may be removed", ] diff --git a/specreduce/background.py b/specreduce/background.py index 2630cd49..0b67976a 100644 --- a/specreduce/background.py +++ b/specreduce/background.py @@ -9,7 +9,7 @@ from astropy.stats import sigma_clip from astropy.utils.decorators import deprecated_attribute -from specreduce.compat import SPECUTILS_LT_2, Spectrum +from specutils import Spectrum from specreduce.core import _ImageParser, MaskingOption, ImageLike from specreduce.extract import _ap_weight_image from specreduce.tracing import Trace, FlatTrace @@ -375,12 +375,9 @@ def bkg_image(self, image=None) -> Spectrum: self._orig_uncty_type ) - if SPECUTILS_LT_2: - kwargs = {} - else: - kwargs = {"spectral_axis_index": arr.ndim - 1} return Spectrum( - arr * image.unit, spectral_axis=image.spectral_axis, uncertainty=uncertainty, **kwargs + arr * image.unit, spectral_axis=image.spectral_axis, uncertainty=uncertainty, + spectral_axis_index=arr.ndim - 1 ) def bkg_spectrum(self, image=None, bkg_statistic=None) -> Spectrum: @@ -400,7 +397,7 @@ def bkg_spectrum(self, image=None, bkg_statistic=None) -> Spectrum: Returns ------- - `~specutils.Spectrum1D` + `~specutils.Spectrum` The background 1D spectrum, with flux and uncertainty expressed in the same units as the input image (or DN if none were provided). """ @@ -436,17 +433,7 @@ def sub_image(self, image=None) -> Spectrum: uncertainty. """ image = self._parse_image(image) - - if not SPECUTILS_LT_2: - return image - self.bkg_image(image) - - # a compare_wcs argument is needed for Spectrum.subtract() in order to - # avoid a TypeError from SpectralCoord when image's spectral axis is in - # pixels. it is not needed when image's spectral axis has physical units - kwargs = {"compare_wcs": None} if image.spectral_axis.unit == u.pix else {} - - # https://docs.astropy.org/en/stable/nddata/mixins/ndarithmetic.html - return image.subtract(self.bkg_image(image), **kwargs) + return image - self.bkg_image(image) def sub_spectrum(self, image=None) -> Spectrum: """ diff --git a/specreduce/calibration_data.py b/specreduce/calibration_data.py index b293d453..b6577bf2 100644 --- a/specreduce/calibration_data.py +++ b/specreduce/calibration_data.py @@ -14,7 +14,7 @@ from astropy.coordinates import SpectralCoord from specutils.utils.wcs_utils import vac_to_air -from specreduce.compat import Spectrum +from specutils import Spectrum __all__ = [ 'get_available_line_catalogs', diff --git a/specreduce/compat.py b/specreduce/compat.py deleted file mode 100644 index 274098d6..00000000 --- a/specreduce/compat.py +++ /dev/null @@ -1,11 +0,0 @@ -import specutils -from astropy.utils import minversion - -__all__ = ["Spectrum"] - -SPECUTILS_LT_2 = not minversion(specutils, "2.0.dev") - -if SPECUTILS_LT_2: - from specutils import Spectrum1D as Spectrum -else: - from specutils import Spectrum # noqa: F401 diff --git a/specreduce/conftest.py b/specreduce/conftest.py index 71b44c53..4caa27a2 100644 --- a/specreduce/conftest.py +++ b/specreduce/conftest.py @@ -8,7 +8,7 @@ from astropy.utils.data import get_pkg_data_filename from specutils import SpectralAxis -from specreduce.compat import SPECUTILS_LT_2, Spectrum +from specutils import Spectrum try: from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS @@ -33,11 +33,7 @@ def _mk_test_data(imgtype, nrows=30, ncols=10): flux = image * u.DN uncert = VarianceUncertainty(image_ones) if imgtype == "spec_no_axis": - if SPECUTILS_LT_2: - kwargs = {} - else: - kwargs = {"spectral_axis_index": image.ndim - 1} - image = Spectrum(flux, uncertainty=uncert, **kwargs) + image = Spectrum(flux, uncertainty=uncert, spectral_axis_index=image.ndim - 1) else: # "spec" image = Spectrum(flux, spectral_axis=np.arange(ncols) * u.um, uncertainty=uncert) return image @@ -77,15 +73,10 @@ def all_images(): sax = SpectralAxis(np.linspace(14.377, 3.677, flux.shape[-1]) * u.um) unc = VarianceUncertainty(np.random.rand(*flux.shape)) - if SPECUTILS_LT_2: - kwargs = {} - else: - kwargs = {"spectral_axis_index": img.ndim - 1} - all_images = {} all_images['arr'] = img all_images['s1d'] = Spectrum(flux, spectral_axis=sax, uncertainty=unc) - all_images['s1d_pix'] = Spectrum(flux, uncertainty=unc, **kwargs) + all_images['s1d_pix'] = Spectrum(flux, uncertainty=unc, spectral_axis_index=img.ndim - 1) all_images['ccd'] = CCDData(img, uncertainty=unc, unit=flux.unit) all_images['ndd'] = NDData(img, uncertainty=unc, unit=flux.unit) all_images['qnt'] = img * flux.unit diff --git a/specreduce/core.py b/specreduce/core.py index c3a6dcbd..2fc9b36d 100644 --- a/specreduce/core.py +++ b/specreduce/core.py @@ -9,7 +9,7 @@ from astropy import units as u from astropy.nddata import VarianceUncertainty, NDData -from specreduce.compat import SPECUTILS_LT_2, Spectrum +from specutils import Spectrum __all__ = ["SpecreduceOperation"] @@ -29,7 +29,7 @@ class _ImageParser: that are missing in the provided image with generic values. Accepted image types are: - - `~specutils.Spectrum1D` (preferred) + - `~specutils.Spectrum` (preferred) - `~astropy.nddata.ccddata.CCDData` - `~astropy.nddata.ndddata.NDDData` - `~astropy.units.quantity.Quantity` @@ -148,13 +148,9 @@ def _get_data_from_image( spectral_axis = getattr(image, "spectral_axis", np.arange(img.shape[disp_axis]) * u.pix) - if SPECUTILS_LT_2: - kwargs = {} - else: - kwargs = {"spectral_axis_index": img.ndim - 1} img = Spectrum( img * unit, spectral_axis=spectral_axis, uncertainty=uncertainty, mask=mask, - **kwargs + spectral_axis_index=img.ndim - 1 ) return img diff --git a/specreduce/extract.py b/specreduce/extract.py index 62c7cd39..ab8f377e 100644 --- a/specreduce/extract.py +++ b/specreduce/extract.py @@ -11,7 +11,7 @@ from scipy.integrate import trapezoid from scipy.interpolate import RectBivariateSpline -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.core import SpecreduceOperation, ImageLike, MaskingOption from specreduce.tracing import Trace, FlatTrace @@ -169,7 +169,7 @@ class BoxcarExtract(SpecreduceOperation): Returns ------- - spec : `~specutils.Spectrum1D` + spec : `~specutils.Spectrum` The extracted 1d spectrum expressed in DN and pixel units """ @@ -666,7 +666,7 @@ def __call__( Returns ------- - spec_1d : `~specutils.Spectrum1D` + spec_1d : `~specutils.Spectrum` The final, Horne extracted 1D spectrum. """ image = image if image is not None else self.image diff --git a/specreduce/fluxcal.py b/specreduce/fluxcal.py index dc9cb54c..3449513a 100644 --- a/specreduce/fluxcal.py +++ b/specreduce/fluxcal.py @@ -6,7 +6,7 @@ from astropy.table import Table from scipy.interpolate import UnivariateSpline -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.core import SpecreduceOperation diff --git a/specreduce/line_matching.py b/specreduce/line_matching.py index d54de1c2..f8f1b807 100644 --- a/specreduce/line_matching.py +++ b/specreduce/line_matching.py @@ -12,7 +12,7 @@ from gwcs.wcs import WCS as gWCS from specutils.fitting import find_lines_threshold, fit_lines -from specreduce.compat import Spectrum +from specutils import Spectrum __all__ = ["find_arc_lines", "match_lines_wcs"] diff --git a/specreduce/tests/test_background.py b/specreduce/tests/test_background.py index d4d99991..0aaf49cf 100644 --- a/specreduce/tests/test_background.py +++ b/specreduce/tests/test_background.py @@ -4,7 +4,7 @@ from astropy.nddata import NDData, VarianceUncertainty, StdDevUncertainty, InverseVariance from specreduce.background import Background -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.tracing import FlatTrace, ArrayTrace diff --git a/specreduce/tests/test_extract.py b/specreduce/tests/test_extract.py index 34c145d7..4215140e 100644 --- a/specreduce/tests/test_extract.py +++ b/specreduce/tests/test_extract.py @@ -12,7 +12,7 @@ from astropy.tests.helper import assert_quantity_allclose from specreduce.background import Background -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.extract import BoxcarExtract, HorneExtract, OptimalExtract, _align_along_trace from specreduce.tracing import FitTrace, FlatTrace, ArrayTrace diff --git a/specreduce/tests/test_image_parsing.py b/specreduce/tests/test_image_parsing.py index f10f6449..010df003 100644 --- a/specreduce/tests/test_image_parsing.py +++ b/specreduce/tests/test_image_parsing.py @@ -1,7 +1,7 @@ import numpy as np from astropy import units as u -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.core import _ImageParser from specreduce.extract import HorneExtract from specreduce.tracing import FlatTrace diff --git a/specreduce/tests/test_line_matching.py b/specreduce/tests/test_line_matching.py index e55f1a1c..c70af135 100644 --- a/specreduce/tests/test_line_matching.py +++ b/specreduce/tests/test_line_matching.py @@ -8,7 +8,7 @@ from specutils.fitting import fit_generic_continuum from specreduce.calibration_data import load_pypeit_calibration_lines -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.extract import BoxcarExtract from specreduce.line_matching import match_lines_wcs, find_arc_lines from specreduce.tracing import FlatTrace diff --git a/specreduce/tests/test_utils.py b/specreduce/tests/test_utils.py index df815dff..43408603 100644 --- a/specreduce/tests/test_utils.py +++ b/specreduce/tests/test_utils.py @@ -4,7 +4,7 @@ from astropy.modeling import fitting, models from astropy.nddata import NDData -from specreduce.compat import SPECUTILS_LT_2, Spectrum +from specutils import Spectrum from specreduce.tracing import FitTrace from specreduce.utils.utils import measure_cross_dispersion_profile @@ -61,11 +61,7 @@ def test_measure_cross_dispersion_profile(self, pixel, width): images.append(dat) # test unitless images.append(dat * u.DN) images.append(NDData(dat * u.DN)) - if SPECUTILS_LT_2: - kwargs = {} - else: - kwargs = {"spectral_axis_index": dat.ndim - 1} - images.append(Spectrum(flux=dat * u.DN, **kwargs)) + images.append(Spectrum(flux=dat * u.DN, spectral_axis_index=dat.ndim - 1)) for img in images: diff --git a/specreduce/tests/test_wavecal1d.py b/specreduce/tests/test_wavecal1d.py index 995cb1a5..93b46676 100644 --- a/specreduce/tests/test_wavecal1d.py +++ b/specreduce/tests/test_wavecal1d.py @@ -8,7 +8,7 @@ from matplotlib.figure import Figure from numpy import array -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.wavecal1d import WavelengthCalibration1D ref_pixel = 250 diff --git a/specreduce/tests/test_wavesol1d.py b/specreduce/tests/test_wavesol1d.py index 72c4081c..fcc524bf 100644 --- a/specreduce/tests/test_wavesol1d.py +++ b/specreduce/tests/test_wavesol1d.py @@ -6,7 +6,7 @@ from astropy.nddata import StdDevUncertainty from gwcs import wcs from specreduce.wavesol1d import _diff_poly1d, WavelengthSolution1D -from specreduce.compat import Spectrum +from specutils import Spectrum ref_pixel = 250.0 diff --git a/specreduce/wavecal1d.py b/specreduce/wavecal1d.py index 3c7cc382..6f9d7894 100644 --- a/specreduce/wavecal1d.py +++ b/specreduce/wavecal1d.py @@ -13,7 +13,7 @@ from scipy.spatial import KDTree from specreduce.calibration_data import load_pypeit_calibration_lines -from specreduce.compat import Spectrum +from specutils import Spectrum from specreduce.line_matching import find_arc_lines __all__ = ["WavelengthCalibration1D"] diff --git a/specreduce/wavelength_calibration.py b/specreduce/wavelength_calibration.py index 8d4ad620..b011f5a4 100644 --- a/specreduce/wavelength_calibration.py +++ b/specreduce/wavelength_calibration.py @@ -8,7 +8,7 @@ from gwcs import coordinate_frames as cf from gwcs import wcs -from specreduce.compat import Spectrum +from specutils import Spectrum __all__ = [ 'WavelengthCalibration1D' @@ -29,7 +29,7 @@ class WavelengthCalibration1D(): def __init__(self, input_spectrum, matched_line_list=None, line_pixels=None, line_wavelengths=None, catalog=None, input_model=Linear1D(), fitter=None): """ - input_spectrum: `~specutils.Spectrum1D` + input_spectrum: `~specutils.Spectrum` A one-dimensional Spectrum calibration spectrum from an arc lamp or similar. matched_line_list: `~astropy.table.QTable`, optional An `~astropy.table.QTable` table with (minimally) columns named diff --git a/specreduce/wavesol1d.py b/specreduce/wavesol1d.py index 785f66f5..fab8bc9e 100644 --- a/specreduce/wavesol1d.py +++ b/specreduce/wavesol1d.py @@ -11,7 +11,7 @@ from numpy.typing import ArrayLike, NDArray from scipy.interpolate import interp1d -from specreduce.compat import Spectrum +from specutils import Spectrum __all__ = ["WavelengthSolution1D"] diff --git a/tox.ini b/tox.ini index aeb093cd..f688ad5c 100644 --- a/tox.ini +++ b/tox.ini @@ -47,7 +47,7 @@ deps = oldestdeps: scipy==1.10.* oldestdeps: matplotlib==3.7.* oldestdeps: photutils==1.0.* - oldestdeps: specutils==1.9.* + oldestdeps: specutils==2.0.* # The following indicates which extras_require from setup.cfg will be installed extras = From 6e76bf8e69950bb237c8b0fd090479450b52d81b Mon Sep 17 00:00:00 2001 From: Hannu Parviainen Date: Sun, 1 Feb 2026 20:15:50 +0000 Subject: [PATCH 2/4] Bumped minimum `scipy` version for oldesteps to 1.14 in `tox.ini`. This is the minimum required version for specutils v2. --- tox.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f688ad5c..164d4c48 100644 --- a/tox.ini +++ b/tox.ini @@ -44,7 +44,7 @@ deps = oldestdeps: numpy==1.24.* oldestdeps: astropy==5.3.* - oldestdeps: scipy==1.10.* + oldestdeps: scipy==1.14.* oldestdeps: matplotlib==3.7.* oldestdeps: photutils==1.0.* oldestdeps: specutils==2.0.* From 4ff31fd6fd749cf252c287cd7d3569d09b43283e Mon Sep 17 00:00:00 2001 From: Hannu Parviainen Date: Sun, 1 Feb 2026 20:20:50 +0000 Subject: [PATCH 3/4] Bumped minimum versions of `astropy` to 6.0 and `scipy` to 1.14 in `pyproject.toml` and `tox.ini` for specutils 2 compatibility. --- pyproject.toml | 4 ++-- tox.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 455a443c..3b741a23 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,8 +10,8 @@ readme = "README.rst" requires-python = ">=3.11" dependencies = [ "numpy>=1.24", - "astropy>=5.3", - "scipy>=1.10", + "astropy>=6.0", + "scipy>=1.14", "specutils>=2.0", "matplotlib>=3.10", "gwcs", diff --git a/tox.ini b/tox.ini index 164d4c48..247259ac 100644 --- a/tox.ini +++ b/tox.ini @@ -43,7 +43,7 @@ deps = devdeps: git+https://github.com/spacetelescope/synphot_refactor.git#egg=synphot oldestdeps: numpy==1.24.* - oldestdeps: astropy==5.3.* + oldestdeps: astropy==6.0.* oldestdeps: scipy==1.14.* oldestdeps: matplotlib==3.7.* oldestdeps: photutils==1.0.* From 08d5a669f443437f3927dbe7c1d64894db7aa18c Mon Sep 17 00:00:00 2001 From: Hannu Parviainen Date: Sun, 1 Feb 2026 20:40:41 +0000 Subject: [PATCH 4/4] Bumped minimum version of `photutils` to 1.11 in `pyproject.toml` and `tox.ini`. --- pyproject.toml | 4 ++-- tox.ini | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3b741a23..945dd0fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,13 +28,13 @@ docs = [ "sphinx-copybutton", "sphinx-design", "matplotlib>=3.7", - "photutils>=1.0", + "photutils>=1.11", "synphot", "nbsphinx", "ipykernel" ] all = [ - "photutils>=1.0", + "photutils>=1.11", "synphot", ] diff --git a/tox.ini b/tox.ini index 247259ac..687285b9 100644 --- a/tox.ini +++ b/tox.ini @@ -46,7 +46,7 @@ deps = oldestdeps: astropy==6.0.* oldestdeps: scipy==1.14.* oldestdeps: matplotlib==3.7.* - oldestdeps: photutils==1.0.* + oldestdeps: photutils==1.11.* oldestdeps: specutils==2.0.* # The following indicates which extras_require from setup.cfg will be installed