Skip to content

Commit

Permalink
Add tests for more intelligible errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
pp-mo committed Jun 12, 2024
1 parent 9ab26dc commit a4dad3a
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 39 deletions.
2 changes: 1 addition & 1 deletion lib/iris/experimental/ugrid/load.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ def _build_mesh_coords(mesh, cf_var):
# We should probably issue warnings and recover, but that is too much
# work. Raising a more intelligible error is easy to do though.
msg = (
f"mesh data variable {cf_var.name!s} has an invalid "
f"mesh data variable {cf_var.name!r} has an invalid "
f"location={location!r}."
)
raise ValueError(msg)
Expand Down
84 changes: 46 additions & 38 deletions lib/iris/tests/unit/experimental/ugrid/load/test_load_meshes.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,50 +27,58 @@ def tearDownModule():
rmtree(TMP_DIR)


def cdl_to_nc(cdl):
cdl_path = str(TMP_DIR / "tst.cdl")
nc_path = str(TMP_DIR / f"{uuid4()}.nc")
def cdl_to_nc(cdl, tmpdir=None):
if tmpdir is None:
tmpdir = TMP_DIR
cdl_path = str(tmpdir / "tst.cdl")
nc_path = str(tmpdir / f"{uuid4()}.nc")
# Use ncgen to convert this into an actual (temporary) netCDF file.
ncgen_from_cdl(cdl_str=cdl, cdl_path=cdl_path, nc_path=nc_path)
return nc_path


class TestsBasic(tests.IrisTest):
_TEST_CDL_HEAD = """
netcdf mesh_test {
dimensions:
node = 3 ;
face = 1 ;
vertex = 3 ;
levels = 2 ;
variables:
int mesh ;
mesh:cf_role = "mesh_topology" ;
mesh:topology_dimension = 2 ;
mesh:node_coordinates = "node_x node_y" ;
mesh:face_node_connectivity = "face_nodes" ;
float node_x(node) ;
node_x:standard_name = "longitude" ;
float node_y(node) ;
node_y:standard_name = "latitude" ;
int face_nodes(face, vertex) ;
face_nodes:cf_role = "face_node_connectivity" ;
face_nodes:start_index = 0 ;
int levels(levels) ;
float node_data(levels, node) ;
node_data:coordinates = "node_x node_y" ;
node_data:location = "node" ;
node_data:mesh = "mesh" ;
"""

_TEST_CDL_TAIL = """
data:
mesh = 0;
node_x = 0., 2., 1.;
node_y = 0., 0., 1.;
face_nodes = 0, 1, 2;
levels = 1, 2;
node_data = 0., 0., 0.;
}
"""


class TestLoadErrors(tests.IrisTest):
def setUp(self):
self.ref_cdl = """
netcdf mesh_test {
dimensions:
node = 3 ;
face = 1 ;
vertex = 3 ;
levels = 2 ;
variables:
int mesh ;
mesh:cf_role = "mesh_topology" ;
mesh:topology_dimension = 2 ;
mesh:node_coordinates = "node_x node_y" ;
mesh:face_node_connectivity = "face_nodes" ;
float node_x(node) ;
node_x:standard_name = "longitude" ;
float node_y(node) ;
node_y:standard_name = "latitude" ;
int face_nodes(face, vertex) ;
face_nodes:cf_role = "face_node_connectivity" ;
face_nodes:start_index = 0 ;
int levels(levels) ;
float node_data(levels, node) ;
node_data:coordinates = "node_x node_y" ;
node_data:location = "node" ;
node_data:mesh = "mesh" ;
data:
mesh = 0;
node_x = 0., 2., 1.;
node_y = 0., 0., 1.;
face_nodes = 0, 1, 2;
levels = 1, 2;
node_data = 0., 0., 0.;
}
"""
self.ref_cdl = _TEST_CDL_HEAD + _TEST_CDL_TAIL
self.nc_path = cdl_to_nc(self.ref_cdl)

def add_second_mesh(self):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import pytest

import iris
from iris.experimental.ugrid.load import PARSE_UGRID_ON_LOAD

from .test_load_meshes import (
_TEST_CDL_HEAD,
_TEST_CDL_TAIL,
cdl_to_nc,
)


class TestMeshLoad:
def _create_testnc(self, location="node", meshdim="node"):
# Add an extra (possibly mal-formed) mesh data to the testfile.
if location is None:
location_cdl = ""
else:
location_cdl = f'extra_data:location = "{location}" ;'

extra_cdl = f"""
float extra_data(levels, {meshdim}) ;
extra_data:coordinates = "node_x node_y" ;
{location_cdl}
extra_data:mesh = "mesh" ;
"""
# Insert this into the definitions part of the 'standard' testfile CDL
extended_cdl = _TEST_CDL_HEAD + extra_cdl + _TEST_CDL_TAIL
testfile_path = cdl_to_nc(extended_cdl, tmpdir=self.tmpdir)
return testfile_path

@pytest.fixture(params=["nolocation", "badlocation", "baddim"])
def failnc(self, request, tmp_path_factory):
self.param = request.param
kwargs = {}
if self.param == "nolocation":
kwargs["location"] = None
elif self.param == "badlocation":
kwargs["location"] = "invalid_location"
elif self.param == "baddim":
kwargs["meshdim"] = "vertex"
else:
raise ValueError(f"unexpected param: {self.param}")

self.tmpdir = tmp_path_factory.mktemp("meshload")
return self._create_testnc(**kwargs)

def test_extrameshvar__ok(self, tmp_path_factory):
# Check that the default cdl construction loads OK
self.tmpdir = tmp_path_factory.mktemp("meshload")
testnc = self._create_testnc()
with PARSE_UGRID_ON_LOAD.context():
iris.load(testnc)

def test_extrameshvar__fail(self, failnc):
# Check that the expected errors are raised in various cases.
param = self.param
if param == "nolocation":
match_msg = (
"mesh data variable 'extra_data' has an " "invalid location='<empty>'."
)
elif param == "badlocation":
match_msg = (
"mesh data variable 'extra_data' has an "
"invalid location='invalid_location'."
)
elif param == "baddim":
match_msg = (
"mesh data variable 'extra_data' does not have the node mesh "
"dimension 'node', in its dimensions."
)
else:
raise ValueError(f"unexpected param: {param}")

with PARSE_UGRID_ON_LOAD.context():
with pytest.raises(ValueError, match=match_msg):
iris.load(failnc)

0 comments on commit a4dad3a

Please sign in to comment.