diff --git a/.github/workflows/tox-tests.yml b/.github/workflows/tox-tests.yml index a331160..f8c940a 100644 --- a/.github/workflows/tox-tests.yml +++ b/.github/workflows/tox-tests.yml @@ -35,20 +35,20 @@ jobs: linux: py310-test-oldestdeps toxargs: -v - - name: Python 3.10 on Windows with minimal dependencies - windows: py310-test + - name: Python 3.11 on Windows with minimal dependencies + windows: py311-test toxargs: -v - - name: Python 3.10 on OSX with minimal dependencies - macos: py310-test + - name: Python 3.11 on OSX with minimal dependencies + macos: py311-test toxargs: -v - - name: Python 3.11 on Linux with all dependencies, remote data, and coverage - linux: py311-test-alldeps-cov + - name: Python 3.12 on Linux with all dependencies, remote data, and coverage + linux: py312-test-alldeps-cov coverage: codecov toxargs: -v posargs: --remote-data=any - - name: (Allowed Failure) Python 3.12 on Linux with dev dependencies - linux: py312-test-devdeps + - name: (Allowed Failure) Python 3.13 on Linux with dev dependencies + linux: py313-test-devdeps toxargs: -v diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 16476ed..6e500b7 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -5,7 +5,7 @@ build: apt_packages: - graphviz tools: - python: "3.11" + python: "3.13" sphinx: builder: html diff --git a/conftest.py b/conftest.py index 3d6b45d..4c3f853 100644 --- a/conftest.py +++ b/conftest.py @@ -1,4 +1,12 @@ -"""Need to repeat the astropy header config here for tox.""" +# This file is used to configure the behavior of pytest + +import numpy as np +import pytest +from astropy import units as u +from astropy.io import fits +from astropy.nddata import CCDData, NDData, VarianceUncertainty +from astropy.utils.data import get_pkg_data_filename +from specutils import Spectrum1D, SpectralAxis try: from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS @@ -7,6 +15,103 @@ ASTROPY_HEADER = False +# Test image is comprised of 30 rows with 10 columns each. Row content +# is row index itself. This makes it easy to predict what should be the +# value extracted from a region centered at any arbitrary Y position. +def _mk_test_data(imgtype, nrows=30, ncols=10): + image_ones = np.ones(shape=(nrows, ncols)) + image = image_ones.copy() + for j in range(nrows): + image[j, ::] *= j + if imgtype == "raw": + pass # no extra processing + elif imgtype == "ccddata": + image = CCDData(image, unit=u.Jy) + else: # spectrum + flux = image * u.DN + uncert = VarianceUncertainty(image_ones) + if imgtype == "spec_no_axis": + image = Spectrum1D(flux, uncertainty=uncert) + else: # "spec" + image = Spectrum1D(flux, spectral_axis=np.arange(ncols) * u.um, uncertainty=uncert) + return image + + +@pytest.fixture +def mk_test_img_raw(): + return _mk_test_data("raw") + + +@pytest.fixture +def mk_test_img(): + return _mk_test_data("ccddata") + + +@pytest.fixture +def mk_test_spec_no_spectral_axis(): + return _mk_test_data("spec_no_axis") + + +@pytest.fixture +def mk_test_spec_with_spectral_axis(): + return _mk_test_data("spec") + + +# Test data file already transposed like this: +# fn = download_file('https://stsci.box.com/shared/static/exnkul627fcuhy5akf2gswytud5tazmw.fits', cache=True) # noqa: E501 +# img = fits.getdata(fn).T +@pytest.fixture +def all_images(): + np.random.seed(7) + + filename = get_pkg_data_filename( + "data/transposed_det_image_seq5_MIRIMAGE_P750Lexp1_s2d.fits", package="specreduce.tests") + img = fits.getdata(filename) + flux = img * (u.MJy / u.sr) + sax = SpectralAxis(np.linspace(14.377, 3.677, flux.shape[-1]) * u.um) + unc = VarianceUncertainty(np.random.rand(*flux.shape)) + + all_images = {} + all_images['arr'] = img + all_images['s1d'] = Spectrum1D(flux, spectral_axis=sax, uncertainty=unc) + all_images['s1d_pix'] = Spectrum1D(flux, uncertainty=unc) + 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 + return all_images + + +@pytest.fixture +def spec1d(): + np.random.seed(7) + flux = np.random.random(50)*u.Jy + sa = np.arange(0, 50)*u.pix + spec = Spectrum1D(flux, spectral_axis=sa) + return spec + + +@pytest.fixture +def spec1d_with_emission_line(): + np.random.seed(7) + sa = np.arange(0, 200)*u.pix + flux = (np.random.randn(200) + + 10*np.exp(-0.01*((sa.value-130)**2)) + + sa.value/100) * u.Jy + spec = Spectrum1D(flux, spectral_axis=sa) + return spec + + +@pytest.fixture +def spec1d_with_absorption_line(): + np.random.seed(7) + sa = np.arange(0, 200)*u.pix + flux = (np.random.randn(200) - + 10*np.exp(-0.01*((sa.value-130)**2)) + + sa.value/100) * u.Jy + spec = Spectrum1D(flux, spectral_axis=sa) + return spec + + def pytest_configure(config): if ASTROPY_HEADER: diff --git a/docs/conf.py b/docs/conf.py index 6649e7f..cf78023 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -28,6 +28,8 @@ import sys import datetime +import sphinx + from specreduce import __version__ try: @@ -36,6 +38,14 @@ print('ERROR: the documentation requires the sphinx-astropy package to be installed') sys.exit(1) +# xref: https://github.com/sphinx-doc/sphinx/issues/13232#issuecomment-2608708175 +if sys.version_info[:2] >= (3, 13) and sphinx.version_info[:2] < (8, 2): + import pathlib + + from sphinx.util.typing import _INVALID_BUILTIN_CLASSES + + _INVALID_BUILTIN_CLASSES[pathlib.Path] = "pathlib.Path" + # -- General configuration ---------------------------------------------------- # By default, highlight as Python 3. diff --git a/pyproject.toml b/pyproject.toml index a4c92b5..6f661c0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -76,21 +76,19 @@ filterwarnings = [ "ignore:numpy\\.ufunc size changed:RuntimeWarning", "ignore:numpy\\.ndarray size changed:RuntimeWarning", "ignore:Can\\'t import specreduce_data package", + "ignore:.*unclosed