Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make xESMF optional #337

Merged
merged 9 commits into from Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
27 changes: 11 additions & 16 deletions .github/workflows/main.yml
aulemahal marked this conversation as resolved.
Show resolved Hide resolved
Expand Up @@ -52,24 +52,23 @@ jobs:
python -m tox -e lint

test-pypi:
name: Test with Python${{ matrix.python-version }} (PyPI/tox)
name: Test with Python${{ matrix.python-version }} (PyPI/tox, no ESMF)
needs: lint
runs-on: ubuntu-latest
env:
COVERALLS_PARALLEL: true
COVERALLS_SERVICE_NAME: github
esmf-version: 8.4.2
strategy:
matrix:
include:
- python-version: "3.9"
tox-build: "py39-esmpy-coveralls"
tox-build: "py39-coveralls"
- python-version: "3.10"
tox-build: "py310-esmpy-coveralls"
tox-build: "py310-coveralls"
- python-version: "3.11"
tox-build: "py311-esmpy-coveralls"
tox-build: "py311-coveralls"
# - python-version: "3.12"
# tox-build: "py312-esmpy-coveralls"
# tox-build: "py312-coveralls"
defaults:
run:
shell: bash -l {0}
Expand All @@ -79,21 +78,17 @@ jobs:
with:
egress-policy: audit
- uses: actions/checkout@v4.1.1
- name: Setup Conda (Micromamba) with Python ${{ matrix.python-version }}
uses: mamba-org/setup-micromamba@v1.8.0
- name: Set up Python${{ matrix.python-version }}
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
cache-downloads: true
environment-name: xscen-pypi
create-args: >-
esmf=${{ env.esmf-version }}
mamba
python=${{ matrix.python-version }}
tox
python-version: ${{ matrix.python-version }}
- name: Install tox
run: |
python -m pip install tox~=4.0
- name: Test with tox
run: |
python -m tox -e ${{ matrix.tox-build }}
env:
ESMF_VERSION: ${{ env.esmf-version }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: run-Python${{ matrix.python-version }}

Expand Down
1 change: 1 addition & 0 deletions CHANGES.rst
Expand Up @@ -10,6 +10,7 @@ New features and enhancements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
* Added a new argument ``indicators_kw`` to ``xs.ensembles.build_partition_data``. (:pull:`315`).
* `xscen` is `Semantic Versioning 2.0.0 <https://semver.org/spec/v2.0.0.html>`_ compliant. (:pull:`319`).
* `xesmf` made an optional dependency, making `xscen` easier to install with `pip`. (:pull:`337`).

Internal changes
^^^^^^^^^^^^^^^^
Expand Down
4 changes: 3 additions & 1 deletion pyproject.toml
Expand Up @@ -64,7 +64,6 @@ dependencies = [
"toolz",
"xarray<2023.11.0", # FIXME: Remove when pandas 2.2 is released and xclim is fixed.
"xclim>=0.46.0",
"xesmf>=0.7",
"zarr"
]

Expand Down Expand Up @@ -105,6 +104,9 @@ docs = [
"sphinx-rtd-theme>=1.0",
"sphinxcontrib-napoleon"
]
extra = [
"xesmf>=0.7"
]

[project.urls]
"About Ouranos" = "https://www.ouranos.ca/en/"
Expand Down
7 changes: 7 additions & 0 deletions tests/test_aggregate.py
Expand Up @@ -8,6 +8,11 @@
import xscen as xs
from xscen.testing import datablock_3d

try:
import xesmf as xe
except ImportError:
xe = None


class TestClimatologicalMean:
def test_future_warning(self):
Expand Down Expand Up @@ -414,6 +419,8 @@ class TestSpatialMean:
)
@pytest.mark.parametrize("lonstart", [-70, -30, 0])
def test_global(self, lonstart, method, exp):
if method == "xesmf" and xe is None:
pytest.skip("xesmf needed for testing averaging with method xesmf")
ds = datablock_3d(
np.array([[[0, 1, 2], [1, 2, 3], [2, 3, 4]]] * 3, "float"),
"tas",
Expand Down
9 changes: 7 additions & 2 deletions tests/test_ensembles.py
Expand Up @@ -5,7 +5,11 @@
import pytest
import xarray as xr
import xclim as xc
import xesmf

try:
import xesmf as xe
except ImportError:
xe = None
from xclim.testing.helpers import test_timeseries as timeseries

import xscen as xs
Expand Down Expand Up @@ -1064,6 +1068,7 @@ def test_attribute_weight_error(self):


class TestEnsemblePartition:
@pytest.mark.skipif(xe is None, reason="xesmf needed for testing regrdding")
def test_build_partition_data(self, samplecat, tmp_path):
# test subset
datasets = samplecat.search(variable="tas").to_dataset_dict(
Expand All @@ -1083,7 +1088,7 @@ def test_build_partition_data(self, samplecat, tmp_path):
assert [i for i in ds.data_vars] == ["tg_mean"]

# test regrid
ds_grid = xesmf.util.cf_grid_2d(-75, -74, 0.25, 45, 48, 0.55)
ds_grid = xe.util.cf_grid_2d(-75, -74, 0.25, 45, 48, 0.55)
datasets = samplecat.search(variable="tas", member="r1i1p1f1").to_dataset_dict(
xarray_open_kwargs={"engine": "h5netcdf"}
)
Expand Down
6 changes: 6 additions & 0 deletions tests/test_regrid.py
@@ -1,5 +1,10 @@
import numpy as np
import pytest

try:
import xesmf as xe
except ImportError:
xe = None
from xscen.regrid import create_bounds_rotated_pole, regrid_dataset
from xscen.testing import datablock_3d

Expand All @@ -22,6 +27,7 @@ def test_create_bounds_rotated_pole():
np.testing.assert_allclose(bnds.lat_bounds[-1, -1, 1], 42.5)


@pytest.mark.skipif(xe is None, reason="xesmf needed for testing regrdding")
class TestRegridDataset:
def test_simple(self, tmp_path):
dsout = datablock_3d(
Expand Down
15 changes: 2 additions & 13 deletions tox.ini
aulemahal marked this conversation as resolved.
Show resolved Hide resolved
Expand Up @@ -2,7 +2,7 @@
min_version = 4.0
envlist =
lint
py{39,310,311,312}-esmpy
py{39,310,311,312}
docs-esmpy
requires =
babel
Expand Down Expand Up @@ -55,30 +55,19 @@ commands =
pytest --xdoctest xscen --durations=10 {posargs}

[testenv]
description = Run tests with pytest under {basepython} (Anaconda distribution)
description = Run tests with pytest under {basepython} (PyPI only)
setenv =
COV_CORE_SOURCE =
PYTEST_ADDOPTS = --color=yes --cov=xscen --strict-markers --verbose
PYTHONPATH = {toxinidir}
passenv =
COVERALLS_*
ESMFMKFILE
ESMF_VERSION
GITHUB_*
download = true
deps =
coveralls: coveralls
esmpy: git+https://github.com/esmf-org/esmf.git@v{env:ESMF_VERSION}\#subdirectory=src/addon/esmpy
extras =
dev
conda_channels =
conda-forge
defaults
conda_deps =
pytest
pytest-cov
xdoctest
conda_env = environment.yml
install_command = python -m pip install --no-user {opts} {packages}
commands_pre =
pip list
Expand Down
11 changes: 10 additions & 1 deletion xscen/aggregate.py
Expand Up @@ -18,7 +18,11 @@
import xarray as xr
import xclim as xc
import xclim.core.calendar
import xesmf as xe

try:
import xesmf as xe
except ImportError:
xe = None
from xclim.core.indicator import Indicator

from .config import parse_config
Expand Down Expand Up @@ -930,6 +934,11 @@ def spatial_mean( # noqa: C901

# Uses xesmf.SpatialAverager
elif method == "xesmf":
if xe is None:
raise ImportError(
"Method xesmf requires xESMF to work, please install that package."
)

# If the region is a bounding box, call shapely and geopandas to transform it into an input compatible with xesmf
if region["method"] == "bbox":
polygon_geom = shapely.box(
Expand Down
15 changes: 13 additions & 2 deletions xscen/regrid.py
Expand Up @@ -11,7 +11,13 @@
import cf_xarray as cfxr
import numpy as np
import xarray as xr
import xesmf as xe

try:
import xesmf as xe
from xesmf.frontend import Regridder
except ImportError:
xe = None
Regridder = "xesmf.Regridder"

from .config import parse_config

Expand Down Expand Up @@ -75,6 +81,11 @@ def regrid_dataset( # noqa: C901
--------
xesmf.regridder, xesmf.util.cf_grid_2d
"""
if xe is None:
raise ImportError(
"xscen's regridding functionality requires xESMF to work, please install that package."
)

regridder_kwargs = regridder_kwargs or {}

ds_grids = [] # list of target grids
Expand Down Expand Up @@ -293,7 +304,7 @@ def _regridder(
method: str = "bilinear",
unmapped_to_nan: Optional[bool] = True,
**kwargs,
) -> xe.frontend.Regridder:
) -> Regridder:
"""Call to xesmf Regridder with a few default arguments.

Parameters
Expand Down