diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 6eb0518b..b3a2636f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -48,6 +48,29 @@ jobs: name: codecov-umbrella fail_ci_if_error: false + no-optional-deps: + name: no-optional-deps + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: conda-incubator/setup-miniconda@v2 + with: + channels: conda-forge + mamba-version: "*" + activate-environment: cf_xarray_test + auto-update-conda: false + python-version: ${{ matrix.python-version }} + - name: Set up conda environment + shell: bash -l {0} + run: | + mamba env update -f ci/environment-no-optional-deps.yml + python -m pip install -e . + conda list + - name: Run Tests + shell: bash -l {0} + run: | + pytest -n 2 + upstream-dev: name: upstream-dev runs-on: ubuntu-latest diff --git a/cf_xarray/tests/test_units.py b/cf_xarray/tests/test_units.py new file mode 100644 index 00000000..17398d4b --- /dev/null +++ b/cf_xarray/tests/test_units.py @@ -0,0 +1,60 @@ +r"""Tests the operation of cf_xarray's ported unit support code. + +Reused with modification from MetPy under the terms of the BSD 3-Clause License. +Copyright (c) 2017 MetPy Developers. +""" + +import pytest + +pytest.importorskip("pint") + +from ..units import units + + +def test_added_degrees_units(): + """Test that our added degrees units are present in the registry.""" + # Test equivalence of abbreviations/aliases to our defined names + assert str(units("degrees_N").units) == "degrees_north" + assert str(units("degreesN").units) == "degrees_north" + assert str(units("degree_north").units) == "degrees_north" + assert str(units("degree_N").units) == "degrees_north" + assert str(units("degreeN").units) == "degrees_north" + assert str(units("degrees_E").units) == "degrees_east" + assert str(units("degreesE").units) == "degrees_east" + assert str(units("degree_east").units) == "degrees_east" + assert str(units("degree_E").units) == "degrees_east" + assert str(units("degreeE").units) == "degrees_east" + + # Test equivalence of our defined units to base units + assert units("degrees_north") == units("degrees") + assert units("degrees_north").to_base_units().units == units.radian + assert units("degrees_east") == units("degrees") + assert units("degrees_east").to_base_units().units == units.radian + + +def test_gpm_unit(): + """Test that the gpm unit does alias to meters.""" + x = 1 * units("gpm") + assert str(x.units) == "meter" + + +def test_psu_unit(): + """Test that the psu unit are present in the registry.""" + x = 1 * units("psu") + assert str(x.units) == "practical_salinity_unit" + + +def test_percent_units(): + """Test that percent sign units are properly parsed and interpreted.""" + assert str(units("%").units) == "percent" + + +@pytest.mark.xfail(reason="not supported by pint, yet: hgrecco/pint#1295") +def test_udunits_power_syntax(): + """Test that UDUNITS style powers are properly parsed and interpreted.""" + assert units("m2 s-2").units == units.m ** 2 / units.s ** 2 + + +def test_udunits_power_syntax_parse_units(): + """Test that UDUNITS style powers are properly parsed and interpreted.""" + assert units.parse_units("m2 s-2") == units.m ** 2 / units.s ** 2 diff --git a/cf_xarray/units.py b/cf_xarray/units.py new file mode 100644 index 00000000..4aad7a4f --- /dev/null +++ b/cf_xarray/units.py @@ -0,0 +1,58 @@ +r"""Module to provide unit support via pint approximating UDUNITS/CF. + +Reused with modification from MetPy under the terms of the BSD 3-Clause License. +Copyright (c) 2015,2017,2019 MetPy Developers. +""" +import functools +import re +import warnings + +import pint +from pint import ( # noqa: F401 + DimensionalityError, + UndefinedUnitError, + UnitStrippedWarning, +) + +# Create registry, with preprocessors for UDUNITS-style powers (m2 s-2) and percent signs +units = pint.UnitRegistry( + autoconvert_offset_to_baseunit=True, + preprocessors=[ + functools.partial( + re.compile( + r"(?<=[A-Za-z])(?![A-Za-z])(?