Skip to content

Commit

Permalink
Make xESMF a required dependency
Browse files Browse the repository at this point in the history
- Move xESMF to the "base" section in the conda env yml files
- Remove all code related to `_has_xesmf()` and move xESMF related imports outside of conditional statements
- Remove conditiondal statements related to xESMF that are no longer needed
- Remove mentions of xESMF being an optional dependency in the getting-started documentation page
- Update tests
  • Loading branch information
tomvothecoder committed Nov 28, 2023
1 parent 577d7b6 commit d0b85ca
Show file tree
Hide file tree
Showing 8 changed files with 17 additions and 94 deletions.
4 changes: 1 addition & 3 deletions conda-env/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,8 @@ dependencies:
- pandas
- python-dateutil
- xarray >=2022.02.0 # This version of Xarray drops support for Python 3.8.
- xgcm
# Optional - enables additional features.
# =========================================
- xesmf >=0.7.0 # Constrained because https://github.com/pangeo-data/xESMF/issues/212.
- xgcm
# Quality Assurance
# ==================
- types-python-dateutil
Expand Down
2 changes: 1 addition & 1 deletion conda-env/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@ dependencies:
- pandas
- python-dateutil
- xarray >=2022.02.0 # This version of Xarray drops support for Python 3.8.
- xesmf >=0.7.0 # Constrained because https://github.com/pangeo-data/xESMF/issues/212.
- xgcm
# Optional - enables additional features.
# =========================================
- xesmf >=0.7.0 # Constrained because https://github.com/pangeo-data/xESMF/issues/212.
- matplotlib-base >=3.7.0
- nc-time-axis=1.4.1
# Documentation
Expand Down
16 changes: 3 additions & 13 deletions docs/getting-started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,14 @@ Installation
The advantage with following this approach is that Mamba will attempt to resolve
dependencies (e.g. ``python >= 3.8``) for compatibility.

To create an ``xcdat`` Mamba environment with ``xesmf`` (a recommended dependency),
To create an ``xcdat`` Mamba environment,
run:

.. code-block:: bash
>>> mamba create -n <ENV_NAME> -c conda-forge xcdat xesmf
>>> mamba create -n <ENV_NAME> -c conda-forge xcdat
>>> mamba activate <ENV_NAME>
Note that ``xesmf`` is an optional dependency, which is required for using ``xesmf``
based horizontal regridding APIs in ``xcdat``. ``xesmf`` is not currently supported
on `Windows`_ because it depends on ``esmpy``, which also does not support Windows.
Windows users can try `WSL2`_ as a workaround.

.. _Windows: https://github.com/conda-forge/esmf-feedstock/issues/64
.. _WSL2: https://docs.microsoft.com/en-us/windows/wsl/install

2. Install ``xcdat`` in an existing Mamba environment (`mamba install`_)

You can also install ``xcdat`` in an existing Mamba environment, granted that Mamba
Expand All @@ -72,9 +64,7 @@ Installation
.. code-block:: bash
>>> mamba activate <ENV_NAME>
>>> mamba install -c conda-forge xcdat xesmf
Note: As above, ``xesmf`` is an optional dependency.
>>> mamba install -c conda-forge xcdat
3. [Optional] Some packages that are commonly used with ``xcdat`` can be installed
either in step 1 or step 2 above:
Expand Down
4 changes: 1 addition & 3 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""Unit test package for xcdat."""
from xarray.core.options import set_options
from xarray.tests import _importorskip, requires_dask # noqa: F401
from xarray.tests import requires_dask # noqa: F401

set_options(warn_for_unclosed_files=False)

has_xesmf, requires_xesmf = _importorskip("xesmf")
29 changes: 2 additions & 27 deletions tests/test_regrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,8 @@
import pytest
import xarray as xr

from tests import fixtures, has_xesmf, requires_xesmf
from xcdat.regridder import accessor, base, grid, regrid2, xgcm

if has_xesmf:
from xcdat.regridder import xesmf
from tests import fixtures
from xcdat.regridder import accessor, base, grid, regrid2, xesmf, xgcm

np.set_printoptions(threshold=sys.maxsize, suppress=True)

Expand Down Expand Up @@ -688,7 +685,6 @@ def test_reversed_extract_bounds(self):
assert north[0], north[-1] == (60, 90)


@requires_xesmf
class TestXESMFRegridder:
@pytest.fixture(autouse=True)
def setup(self):
Expand All @@ -697,13 +693,6 @@ def setup(self):
)
self.new_grid = grid.create_uniform_grid(-90, 90, 4.0, -180, 180, 5.0)

@pytest.mark.xfail
def test_raises_error_if_xesmf_is_not_installed(self):
# TODO Find a way to mock the value of `_has_xesmf` to False or
# to remove the `xesmf` module entirely
with pytest.raises(ModuleNotFoundError):
xesmf.XESMFRegridder(self.ds, self.new_grid, "bilinear")

def test_vertical_placeholder(self):
ds = self.ds.copy()

Expand Down Expand Up @@ -1198,7 +1187,6 @@ def test_preserve_mask_from_input(self):

xr.testing.assert_allclose(mask.ts, grid.mask)

@requires_xesmf
def test_horizontal(self):
output_grid = grid.create_gaussian_grid(32)

Expand Down Expand Up @@ -1348,7 +1336,6 @@ def test_vertical_tool_check(self, _get_input_grid):
):
self.ac.vertical("ts", mock_data, tool="dummy", target_data=None) # type: ignore

@requires_xesmf
@pytest.mark.filterwarnings("ignore:.*invalid value.*divide.*:RuntimeWarning")
def test_convenience_methods(self):
ds = fixtures.generate_dataset(
Expand All @@ -1365,18 +1352,6 @@ def test_convenience_methods(self):

assert output_regrid2.ts.shape == (15, 32, 65)

@pytest.mark.xfail
def test_raises_error_if_xesmf_is_not_installed(self):
# TODO Find a way to mock the value of `_has_xesmf` to False or
# to remove the `xesmf` module entirely
ds = fixtures.generate_dataset(
decode_times=True, cf_compliant=False, has_bounds=True
)

out_grid = grid.create_gaussian_grid(32)
with pytest.raises(ModuleNotFoundError):
ds.regridder.horizontal_xesmf("ts", out_grid, method="bilinear")


class TestBase:
def test_preserve_bounds(self):
Expand Down
5 changes: 1 addition & 4 deletions xcdat/regridder/__init__.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from xcdat.regridder.accessor import RegridderAccessor
from xcdat.regridder.regrid2 import Regrid2Regridder
from xcdat.regridder.xesmf import XESMFRegridder
from xcdat.regridder.xgcm import XGCMRegridder
from xcdat.utils import _has_module

_has_xesmf = _has_module("xesmf")
if _has_xesmf:
from xcdat.regridder.xesmf import XESMFRegridder
37 changes: 7 additions & 30 deletions xcdat/regridder/accessor.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,14 @@
import xarray as xr

from xcdat.axis import CFAxisKey, get_dim_coords
from xcdat.regridder import regrid2, xgcm
from xcdat.regridder import regrid2, xesmf, xgcm
from xcdat.regridder.grid import _validate_grid_has_single_axis_dim
from xcdat.utils import _has_module

HorizontalRegridTools = Literal["xesmf", "regrid2"]
HORIZONTAL_REGRID_TOOLS = {"regrid2": regrid2.Regrid2Regridder}

# TODO: Test this conditional.
_has_xesmf = _has_module("xesmf")
if _has_xesmf: # pragma: no cover
from xcdat.regridder import xesmf

HORIZONTAL_REGRID_TOOLS["xesmf"] = xesmf.XESMFRegridder # type: ignore
HORIZONTAL_REGRID_TOOLS = {
"regrid2": regrid2.Regrid2Regridder,
"xesmf": xesmf.XESMFRegridder,
}

VerticalRegridTools = Literal["xgcm"]
VERTICAL_REGRID_TOOLS = {"xgcm": xgcm.XGCMRegridder}
Expand Down Expand Up @@ -179,19 +174,9 @@ def horizontal_xesmf(
stacklevel=2,
)

# TODO: Test this conditional.
if _has_xesmf: # pragma: no cover
regridder = HORIZONTAL_REGRID_TOOLS["xesmf"](
self._ds, output_grid, **options
)
regridder = HORIZONTAL_REGRID_TOOLS["xesmf"](self._ds, output_grid, **options)

return regridder.horizontal(data_var, self._ds)
else: # pragma: no cover
raise ModuleNotFoundError(
"The `xesmf` package is required for horizontal regridding with "
"`xesmf`. Make sure your platform supports `xesmf` and it is installed "
"in your conda environment."
)
return regridder.horizontal(data_var, self._ds)

# TODO Either provide generic `horizontal` and `vertical` methods or tool specific
def horizontal_regrid2(
Expand Down Expand Up @@ -327,14 +312,6 @@ def horizontal(
>>> output_data = ds.regridder.horizontal("ts", output_grid, tool="regrid2")
"""
# TODO: Test this conditional.
if tool == "xesmf" and not _has_xesmf: # pragma: no cover
raise ModuleNotFoundError(
"The `xesmf` package is required for horizontal regridding with "
"`xesmf`. Make sure your platform supports `xesmf` and it is installed "
"in your conda environment."
)

try:
regrid_tool = HORIZONTAL_REGRID_TOOLS[tool]
except KeyError as e:
Expand Down
14 changes: 1 addition & 13 deletions xcdat/regridder/xesmf.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
from typing import Any, Optional

import xarray as xr
import xesmf as xe

from xcdat.regridder.base import BaseRegridder, _preserve_bounds
from xcdat.utils import _has_module

# TODO: Test this conditional.
_has_xesmf = _has_module("xesmf")
if _has_xesmf: # pragma: no cover
import xesmf as xe
else: # pragma: no cover
raise ModuleNotFoundError(
"The `xesmf` package is required for horizontal regridding with `xesmf`. Make "
"sure your platform supports `xesmf` and it is installed in your conda "
"environment."
)


VALID_METHODS = [
"bilinear",
Expand Down

0 comments on commit d0b85ca

Please sign in to comment.