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

Added warning and automatic fix for no bounds #166

Merged
merged 4 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions esmvalcore/cmor/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ class CMORCheck():
automatic_fixes: bool
If True, CMORCheck will try to apply automatic fixes for any
detected error, if possible.
warnings_as_errors: bool, default False
If True, CMORCheck will treat all warnings as errors

Attributes
----------
Expand All @@ -43,7 +45,8 @@ class CMORCheck():
automatic_fixes: bool
If True, CMORCheck will try to apply automatic fixes for any
detected error, if possible.

warnings_as_errors: bool
If True, CMORCheck will treat all warnings as errors
"""

_attr_msg = '{}: {} should be {}, not {}'
Expand All @@ -57,7 +60,8 @@ def __init__(self,
var_info,
frequency=None,
fail_on_error=False,
automatic_fixes=False):
automatic_fixes=False,
warnings_as_errors=False):

self._cube = cube
self._failerr = fail_on_error
Expand All @@ -68,6 +72,7 @@ def __init__(self,
frequency = self._cmor_var.frequency
self.frequency = frequency
self.automatic_fixes = automatic_fixes
self.warnings_as_errors = warnings_as_errors

def check_metadata(self, logger=None):
"""
Expand Down Expand Up @@ -345,8 +350,30 @@ def _check_coord(self, cmor, coord, var_name):
self.report_error(self._attr_msg, var_name, 'units',
cmor.units, coord.units)
self._check_coord_values(cmor, coord, var_name)
self._check_coord_bounds(coord, var_name)
self._check_coord_monotonicity_and_direction(cmor, coord, var_name)

def _check_coord_bounds(self, coord, var_name):
if not coord.has_bounds():
if self.automatic_fixes:
try:
coord.guess_bounds()
except ValueError as ex:
self.report_warning(
'Can not guess bounds for coordinate {0} '
'from var {1}: {2}', coord.var_name, var_name, ex
)
else:
self.report_warning(
'Added guessed bounds to coordinate {0} from var {1}',
coord.var_name, var_name
)
else:
self.report_warning(
'Coordinate {0} from var {1} does not have bounds',
coord.var_name, var_name
)

def _check_coord_monotonicity_and_direction(self, cmor, coord, var_name):
"""Check monotonicity and direction of coordinate."""
if not coord.is_monotonic():
Expand Down Expand Up @@ -573,6 +600,10 @@ def report_warning(self, message, *args):
arguments to format the message string.

"""
if self.warnings_as_errors:
self.report_error(message, *args)
return

msg = message.format(*args)
if self._failerr:
print('WARNING: {0}'.format(msg))
Expand Down
27 changes: 22 additions & 5 deletions tests/unit/cmor/test_cmor_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,16 @@ def test_check(self):
"""Test checks succeeds for a good cube."""
self._check_cube()

def _check_cube(self, automatic_fixes=False, frequency=None):
def _check_cube(self, automatic_fixes=False, frequency=None,
warnings_as_errors=True):
"""Apply checks and optionally automatic fixes to self.cube."""
def checker(cube):
return CMORCheck(
cube,
self.var_info,
automatic_fixes=automatic_fixes,
frequency=frequency)
frequency=frequency,
warnings_as_errors=warnings_as_errors)

self.cube = checker(self.cube).check_metadata()
self.cube = checker(self.cube).check_data()
Expand Down Expand Up @@ -162,7 +164,7 @@ def test_check_bad_standard_name_auto_fix(self):
"""Test check pass for a bad standard_name with automatic fixes."""
self.cube = self.get_cube(self.var_info)
self.cube.standard_name = 'wind_speed'
self._check_cube(automatic_fixes=True)
self._check_cube(automatic_fixes=True, warnings_as_errors=False)
self._check_cube()

def test_check_bad_standard_name(self):
Expand All @@ -175,7 +177,7 @@ def test_check_bad_long_name_auto_fix(self):
"""Test check pass for a bad standard_name with automatic fixes."""
self.cube = self.get_cube(self.var_info)
self.cube.long_name = 'bad_name'
self._check_cube(automatic_fixes=True)
self._check_cube(automatic_fixes=True, warnings_as_errors=False)
self._check_cube()

def test_check_bad_long_name_auto_fix_report_warning(self):
Expand Down Expand Up @@ -262,7 +264,9 @@ def _check_fails_in_metadata(self, automatic_fixes=False, frequency=None):

def _check_warnings_on_metadata(self, automatic_fixes=False):
checker = CMORCheck(
self.cube, self.var_info, automatic_fixes=automatic_fixes
self.cube, self.var_info,
warnings_as_errors=False,
automatic_fixes=automatic_fixes,
)
checker.check_metadata()
self.assertTrue(checker.has_warnings())
Expand Down Expand Up @@ -310,6 +314,18 @@ def test_non_decreasing_fix(self):
self.assertTrue(
iris.util.approx_equal(cube_points[index], reference[index]))

def test_not_bounds(self):
"""Warning if bounds are not available."""
self.cube.coord('longitude').bounds = None
self._check_warnings_on_metadata(automatic_fixes=False)
self.assertFalse(self.cube.coord('longitude').has_bounds())

def test_not_bounds_with_fixes(self):
"""Warning if bounds added with automatic fixes."""
self.cube.coord('longitude').bounds = None
self._check_warnings_on_metadata(automatic_fixes=True)
self.assertTrue(self.cube.coord('longitude').has_bounds())

def test_not_correct_lons(self):
"""Fail if longitudes are not correct in metadata step."""
self.cube = self.cube.intersection(longitude=(-180., 180.))
Expand Down Expand Up @@ -596,6 +612,7 @@ def _construct_array_coord(self, dim_spec):
attributes=coord_atts,
units=unit,
)
coord.guess_bounds()
return coord

@staticmethod
Expand Down