Skip to content
37 changes: 21 additions & 16 deletions lib/iris/fileformats/netcdf/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -592,24 +592,26 @@ def _translate_constraints_to_var_callback(constraints):

Notes
-----
For now, ONLY handles a single NameConstraint with no 'STASH' component.
For now, ONLY handles NameConstraints with no 'STASH' component.

"""
import iris._constraints

constraints = iris._constraints.list_of_constraints(constraints)
result = None
if len(constraints) == 1:
(constraint,) = constraints
if (
isinstance(constraint, iris._constraints.NameConstraint)
and constraint.STASH == "none"
):
# As long as it doesn't use a STASH match, then we can treat it as
# a testing against name properties of cf_var.
# That's just like testing against name properties of a cube, except that they may not all exist.
def inner(cf_datavar):
match = True
if len(constraints) == 0 or not all(
isinstance(constraint, iris._constraints.NameConstraint)
and constraint.STASH == "none"
for constraint in constraints
):
# We can define a var-filtering function to speedup the load, *ONLY* when we
# have some constraints, and all are simple NameConstraints with no STASH.
result = None
else:

def inner(cf_datavar):
match_any_constraint = False
for constraint in constraints:
match_this_constraint = True
for name in constraint._names:
expected = getattr(constraint, name)
if name != "STASH" and expected != "none":
Expand All @@ -620,11 +622,14 @@ def inner(cf_datavar):
continue
actual = getattr(cf_datavar, attr_name, "")
if actual != expected:
match = False
match_this_constraint = False
break
return match
if match_this_constraint:
match_any_constraint = True
break
return match_any_constraint

result = inner
result = inner
return result


Expand Down
7 changes: 7 additions & 0 deletions lib/iris/tests/integration/netcdf/test_general.py
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,13 @@ def test_netcdf_with_NameConstraint(self):
self.assertEqual(len(cubes), 1)
self.assertEqual(cubes[0].var_name, "cdf_temp_dmax_tmean_abs")

def test_netcdf_with_2_NameConstraints(self):
var_names = ["cdf_temp_dmax_tmean_abs", "temp_dmax_tmean_abs"]
constrs = [iris.NameConstraint(var_name=var_name) for var_name in var_names]
cubes = iris.load(self.filename, constrs)
self.assertEqual(len(cubes), 2)
self.assertEqual([cube.var_name for cube in cubes], var_names)

def test_netcdf_with_no_constraint(self):
cubes = iris.load(self.filename)
self.assertEqual(len(cubes), 3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,35 @@ class Test(tests.IrisTest):
def test_multiple_constraints(self):
constrs = [
iris.NameConstraint(standard_name="x_wind"),
iris.NameConstraint(var_name="var1"),
iris.NameConstraint(var_name="var2"),
]
callback = _translate_constraints_to_var_callback(constrs)
result = [callback(var) for var in self.data_variables]
self.assertArrayEqual(result, [True, True, False, True, False])

def test_multiple_constraints_invalid(self):
constrs = [
iris.NameConstraint(standard_name="x_wind"),
iris.NameConstraint(var_name="var1", STASH="m01s00i024"),
]
result = _translate_constraints_to_var_callback(constrs)
self.assertIsNone(result)

def test_multiple_constraints__multiname(self):
# Modify the first constraint to require BOTH var-name and std-name match
constrs = [
iris.NameConstraint(standard_name="x_wind", var_name="var1"),
iris.NameConstraint(var_name="var2"),
]
callback = _translate_constraints_to_var_callback(constrs)
# Add 2 extra vars: one passes both name checks, and the other does not
vars = self.data_variables + [
CFDataVariable("var1", MagicMock(standard_name="x_wind")),
CFDataVariable("var1", MagicMock(standard_name="air_pressure")),
]
result = [callback(var) for var in vars]
self.assertArrayEqual(result, [True, True, False, True, False, True, False])

def test_non_NameConstraint(self):
constr = iris.AttributeConstraint(STASH="m01s00i002")
result = _translate_constraints_to_var_callback(constr)
Expand Down Expand Up @@ -91,6 +115,11 @@ def test_NameConstraint_with_STASH(self):
result = _translate_constraints_to_var_callback(constr)
self.assertIsNone(result)

def test_no_constraints(self):
constrs = []
result = _translate_constraints_to_var_callback(constrs)
self.assertIsNone(result)


if __name__ == "__main__":
tests.main()
Loading