Skip to content

Commit

Permalink
Merge pull request #91 from desihub/scipy-integration-and-other-fixes
Browse files Browse the repository at this point in the history
Scipy integration and other fixes
  • Loading branch information
weaverba137 authored Aug 2, 2024
2 parents da26fc7 + 869b880 commit 875abd0
Show file tree
Hide file tree
Showing 12 changed files with 134 additions and 57 deletions.
41 changes: 20 additions & 21 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,28 @@ jobs:
fail-fast: true
matrix:
os: [ubuntu-latest] # Add more os?
python-version: [3.8, 3.9]
python-version: ['3.8', '3.9']
astropy-version: ['<5.0', '<5.1']
numpy-version: ['<1.20', '<1.21', '<1.22']
scipy-version: ['<1.6', '<1.7']
# matplotlib >= 3.3 brings in a dependency on Pillow, which requires numpy >= 1.21 unless it's pinned to Pillow<10.4.
matplotlib-version: ['<3.4', '<3.5']

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools
python -m pip install pytest pytest-astropy pyyaml
# python -m pip install -r requirements.txt
python -m pip install pytest pytest-astropy pyyaml Pillow\<10.4
python -m pip install 'scipy${{ matrix.scipy-version }}'
python -m pip install 'matplotlib${{ matrix.matplotlib-version }}'
python -m pip install 'astropy${{ matrix.astropy-version }}'
Expand All @@ -59,20 +59,20 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools
python -m pip install pytest pytest-astropy coveralls
python -m pip install pyyaml numpy\<1.21 scipy\<1.6 matplotlib\<3.3 astropy\<5.0
python -m pip install pytest pytest-astropy pyyaml coveralls
python -m pip install Pillow\<10.4 numpy\<1.21 scipy\<1.6 matplotlib\<3.4 astropy\<5.0
- name: Run the test with coverage
run: pytest --cov
Expand All @@ -90,24 +90,23 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.9]
python-version: ['3.8']

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools docutils\<0.18 Sphinx
python -m pip install sphinx-astropy
python -m pip install speclite
python -m pip install --upgrade pip wheel setuptools Sphinx\<8
python -m pip install -e .[docs]
- name: Test the documentation
run: sphinx-build -W --keep-going -b html docs docs/_build/html
Expand All @@ -119,24 +118,24 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest]
python-version: [3.9]
python-version: ['3.10']

steps:
- name: Checkout code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install Python dependencies
run: |
python -m pip install --upgrade pip wheel setuptools flake8
- name: Test the style; failures are allowed
# This is equivalent to an allowed falure.
continue-on-error: true
- name: Test the style
# If allowed failures are needed, uncomment continue-on-error.
# continue-on-error: true
run: flake8 speclite --count --max-line-length=100
52 changes: 52 additions & 0 deletions conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# this contains imports plugins that configure py.test for astropy tests.
# by importing them here in conftest.py they are discoverable by py.test
# no matter how it is invoked within the source tree.

from astropy.version import version as astropy_version
if astropy_version < '3.0':
# With older versions of Astropy, we actually need to import the pytest
# plugins themselves in order to make them discoverable by pytest.
from astropy.tests.pytest_plugins import *
else:
# As of Astropy 3.0, the pytest plugins provided by Astropy are
# automatically made available when Astropy is installed. This means it's
# not necessary to import them here, but we still need to import global
# variables that are used for configuration.
from pytest_astropy_header.display import PYTEST_HEADER_MODULES, TESTED_VERSIONS

from astropy.tests.helper import enable_deprecations_as_exceptions

## Uncomment the following line to treat all DeprecationWarnings as
## exceptions
# enable_deprecations_as_exceptions()

## Uncomment and customize the following lines to add/remove entries from
## the list of packages for which version numbers are displayed when running
## the tests. Making it pass for KeyError is essential in some cases when
## the package uses other astropy affiliated packages.
try:
PYTEST_HEADER_MODULES['Astropy'] = 'astropy'
PYTEST_HEADER_MODULES['Pillow'] = 'PIL'
PYTEST_HEADER_MODULES['PyYAML'] = 'yaml'
del PYTEST_HEADER_MODULES['h5py']
del PYTEST_HEADER_MODULES['Pandas']
except (NameError, KeyError): # NameError is needed to support Astropy < 1.0
pass

## Uncomment the following lines to display the version number of the
## package rather than the version number of Astropy in the top line when
## running the tests.
# import os
#
## This is to figure out the affiliated package version, rather than
## using Astropy's
# try:
# from .version import version
# except ImportError:
# version = 'dev'
#
# try:
# packagename = os.path.basename(os.path.dirname(__file__))
# TESTED_VERSIONS[packagename] = version
# except NameError: # Needed to support Astropy <= 1.0.0
# pass
2 changes: 1 addition & 1 deletion docs/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Operations with Filters

.. automodapi:: speclite.filters
:no-inheritance-diagram:
:skip: get_path_of_data_file
:skip: get_path_of_data_file, trapz, simps

Other Functions
===============
Expand Down
3 changes: 2 additions & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import datetime
import os
import sys
from importlib import import_module

try:
import astropy_helpers
Expand Down Expand Up @@ -84,7 +85,7 @@
# |version| and |release|, also used in various other places throughout the
# built documents.

__import__(setup_cfg['package_name'])
import_module(setup_cfg['package_name'])
package = sys.modules[setup_cfg['package_name']]

# The short X.Y version.
Expand Down
4 changes: 3 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ license = BSD
url = https://speclite.readthedocs.io/
edit_on_github = True
github_project = desihub/speclite
install_requires = astropy scipy pyyaml pytest_astropy_header
install_requires = astropy scipy pyyaml
# version should be PEP440 compatible, e.g. 0.8 or 0.8.dev (http://www.python.org/dev/peps/pep-0440)
version = 0.20.dev

Expand All @@ -36,6 +36,8 @@ version = 0.20.dev
speclite_benchmark = speclite.benchmark:main

[options.extras_require]
test =
pytest-astropy
docs =
sphinx-astropy

Expand Down
14 changes: 8 additions & 6 deletions speclite/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
## the list of packages for which version numbers are displayed when running
## the tests. Making it pass for KeyError is essential in some cases when
## the package uses other astropy affiliated packages.
# try:
# PYTEST_HEADER_MODULES['Astropy'] = 'astropy'
# PYTEST_HEADER_MODULES['scikit-image'] = 'skimage'
# del PYTEST_HEADER_MODULES['h5py']
# except (NameError, KeyError): # NameError is needed to support Astropy < 1.0
# pass
try:
PYTEST_HEADER_MODULES['Astropy'] = 'astropy'
PYTEST_HEADER_MODULES['Pillow'] = 'PIL'
PYTEST_HEADER_MODULES['PyYAML'] = 'yaml'
del PYTEST_HEADER_MODULES['h5py']
del PYTEST_HEADER_MODULES['Pandas']
except (NameError, KeyError): # NameError is needed to support Astropy < 1.0
pass

## Uncomment the following lines to display the version number of the
## package rather than the version number of Astropy in the top line when
Expand Down
14 changes: 8 additions & 6 deletions speclite/filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,11 @@
import numpy as np

import scipy.interpolate
import scipy.integrate

try:
from scipy.integrate import trapezoid as trapz, simpson as simps
except ImportError:
from scipy.integrate import trapz, simps

import astropy.table
import astropy.units
Expand Down Expand Up @@ -267,9 +271,7 @@
_photon_weighted_unit = default_wavelength_unit**2 / _hc_constant.unit

# Map names to integration methods allowed by the convolution methods below.
_filter_integration_methods = dict(
trapz= scipy.integrate.trapz,
simps= scipy.integrate.simps)
_filter_integration_methods = dict(trapz=trapz, simps=simps)

# Group and band names must be valid python identifiers. Although a leading
# underscore is probably not a good idea, it is simpler to stick with a
Expand Down Expand Up @@ -1806,7 +1808,7 @@ def load_filters(*names):
"""
# Replace any group wildcards with the corresponding canonical names.


filters_path = get_path_of_data_file('filters/')


Expand Down Expand Up @@ -1945,7 +1947,7 @@ def load_filter(name, load_from_cache=True, verbose=False):

def plot_filters(responses, wavelength_unit=None,
wavelength_limits=None, wavelength_scale='linear',
legend_loc='upper right', legend_ncols=1,
legend_loc='upper right', legend_ncols=1,
response_limits=None, cmap='nipy_spectral'):
"""Plot one or more filter response curves.
Expand Down
10 changes: 4 additions & 6 deletions speclite/resample.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
"""Resample spectra using interpolation.
"""
from __future__ import print_function, division

import numpy as np
import numpy.ma as ma
import scipy.interpolate
import pkg_resources as pkgr
from packaging import version

if pkgr.parse_version(np.__version__) >= pkgr.parse_version('1.16'):
if version.parse(np.__version__) >= version.parse('1.16'):
import numpy.lib.recfunctions as rfn

def resample(data_in, x_in, x_out, y, data_out=None, kind='linear'):
Expand Down Expand Up @@ -168,7 +166,7 @@ def resample(data_in, x_in, x_out, y, data_out=None, kind='linear'):
for i,y in enumerate(y_names):
y_in[:,i] = data_in[y].filled(np.nan)
else:
if pkgr.parse_version(np.__version__) >= pkgr.parse_version('1.16'):
if version.parse(np.__version__) >= version.parse('1.16'):
# The slicing does not work in numpy 1.16 and above
# we use structured_to_unstructured to get the slice that we care about
y_in = rfn.structured_to_unstructured(
Expand All @@ -178,7 +176,7 @@ def resample(data_in, x_in, x_out, y, data_out=None, kind='linear'):
# View the structured 1D array as a 2D unstructured array (without
# copying any memory).
y_in = y_in.view(y_type).reshape(data_in.shape + y_shape)

# interp1d will only propagate NaNs correctly for certain values of `kind`.
# With numpy = 1.6 or 1.7, only 'nearest' and 'linear' work.
# With numpy = 1.8 or 1.9, 'slinear' and kind = 0 or 1 also work.
Expand Down
2 changes: 0 additions & 2 deletions speclite/tests/test_accumulate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import print_function, division

from astropy.tests.helper import pytest
from ..accumulate import accumulate
import numpy as np
Expand Down
4 changes: 1 addition & 3 deletions speclite/tests/test_filters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
# Licensed under a 3-clause BSD style license - see LICENSE.rst
from __future__ import print_function, division

from astropy.tests.helper import pytest
from ..filters import *

Expand Down Expand Up @@ -261,7 +259,7 @@ def test_wavelength_property():
wlen = [1, 2, 3] * u.Angstrom
meta = dict(group_name='g', band_name='b')
r = FilterResponse(wlen, [0,1,0], meta)
assert np.allclose(r.wavelength, r._wavelength)
assert np.allclose(r.wavelength, r._wavelength)
assert np.allclose(r.wavelength, validate_wavelength_array(wlen))

def test_mag_flux_units():
Expand Down
22 changes: 22 additions & 0 deletions speclite/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import os
from ..utils import package_data


def test_get_path_of_data_file():
data_file = package_data.get_path_of_data_file('filters/twomass-Ks.ecsv')
assert os.path.exists(data_file)


def test_get_path_of_data_dir():
data_dir = package_data.get_path_of_data_dir()
assert os.path.isdir(data_dir)


def test_get_path_of_data_dir_no_importlib(monkeypatch):
data_dir = package_data.get_path_of_data_dir()
def mock_resource(foo, bar):
return data_dir
monkeypatch.setattr(package_data, '_has_importlib', False)
monkeypatch.setattr(package_data, 'resource_filename', mock_resource)
data_dir2 = package_data.get_path_of_data_dir()
assert data_dir2 == data_dir
23 changes: 13 additions & 10 deletions speclite/utils/package_data.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import os

import pkg_resources
_has_importlib = True
try:
from importlib.resources import files
resource_filename = None
except ImportError:
from pkg_resources import resource_filename
_has_importlib = False

# TODO: should make these Path objects

def get_path_of_data_file(data_file) -> str:
def get_path_of_data_file(data_file):
"""convenience wrapper to return location of data file
"""
file_path = pkg_resources.resource_filename(
"speclite", os.path.join("data", f"{data_file}"))
return os.path.join(get_path_of_data_dir(), data_file)

return file_path


def get_path_of_data_dir() -> str:
def get_path_of_data_dir():
"""convenience wrapper to return location of data directory
"""
file_path = pkg_resources.resource_filename("speclite", "data")

return file_path
if _has_importlib:
return str(files('speclite') / 'data')
return resource_filename('speclite', 'data')

0 comments on commit 875abd0

Please sign in to comment.