diff --git a/docs/iris/src/whatsnew/1.8.rst b/docs/iris/src/whatsnew/1.8.rst index 71c6f9fd8a..440d7c7591 100644 --- a/docs/iris/src/whatsnew/1.8.rst +++ b/docs/iris/src/whatsnew/1.8.rst @@ -148,6 +148,12 @@ Bugs fixed * Saving cube collections to NetCDF, where multiple similar aux-factories exist within the cubes, is now carefully handled such that extra file variables are created where required in some cases. +1.8.2 +----- +* A fix to prevent the error: *AttributeError: 'module' object has no attribute 'date2num'*. + This was caused by the function :func:`netcdftime.date2num` being removed from the netCDF4 + package in recent versions. + Deprecations ============ * The original GRIB loader has been deprecated and replaced with a new diff --git a/lib/iris/tests/unit/fileformats/name_loaders/test__build_cell_methods.py b/lib/iris/tests/unit/fileformats/name_loaders/test__build_cell_methods.py index 842a1a6f9b..c6796c81a4 100644 --- a/lib/iris/tests/unit/fileformats/name_loaders/test__build_cell_methods.py +++ b/lib/iris/tests/unit/fileformats/name_loaders/test__build_cell_methods.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2013 - 2014, Met Office +# (C) British Crown Copyright 2013 - 2015, Met Office # # This file is part of Iris. # @@ -27,38 +27,35 @@ import mock +import iris.coords + from iris.fileformats.name_loaders import _build_cell_methods class Tests(tests.IrisTest): - def setUp(self): - patch = mock.patch('iris.coords.CellMethod') - self.mock_CellMethod = patch.start() - self.addCleanup(patch.stop) - def test_nameII_average(self): - av_or_int = ['something average ob bla'] * 3 + av_or_int = ['something average ob bla'] coord_name = 'foo' res = _build_cell_methods(av_or_int, coord_name) - self.mock_CellMethod.assert_called('average', coord_name) + self.assertEqual(res, [iris.coords.CellMethod('mean', 'foo')]) def test_nameIII_averaged(self): - av_or_int = ['something averaged ob bla'] * 3 + av_or_int = ['something averaged ob bla'] coord_name = 'bar' res = _build_cell_methods(av_or_int, coord_name) - self.mock_CellMethod.assert_called('average', coord_name) + self.assertEqual(res, [iris.coords.CellMethod('mean', 'bar')]) def test_nameII_integral(self): - av_or_int = ['something integral ob bla'] * 3 + av_or_int = ['something integral ob bla'] coord_name = 'ensemble' res = _build_cell_methods(av_or_int, coord_name) - self.mock_CellMethod.assert_called('sum', coord_name) + self.assertEqual(res, [iris.coords.CellMethod('sum', 'ensemble')]) def test_nameIII_integrated(self): - av_or_int = ['something integrated ob bla'] * 3 + av_or_int = ['something integrated ob bla'] coord_name = 'time' res = _build_cell_methods(av_or_int, coord_name) - self.mock_CellMethod.assert_called('sum', coord_name) + self.assertEqual(res, [iris.coords.CellMethod('sum', 'time')]) def test_no_averaging(self): av_or_int = ['No foo averaging', @@ -71,6 +68,26 @@ def test_no_averaging(self): res = _build_cell_methods(av_or_int, coord_name) self.assertEqual(res, [None] * len(av_or_int)) + def test_nameII_mixed(self): + av_or_int = ['something integral ob bla', + 'no averaging', + 'other average'] + coord_name = 'ensemble' + res = _build_cell_methods(av_or_int, coord_name) + self.assertEqual(res, [iris.coords.CellMethod('sum', 'ensemble'), + None, + iris.coords.CellMethod('mean', 'ensemble')]) + + def test_nameIII_mixed(self): + av_or_int = ['something integrated ob bla', + 'no averaging', + 'other averaged'] + coord_name = 'ensemble' + res = _build_cell_methods(av_or_int, coord_name) + self.assertEqual(res, [iris.coords.CellMethod('sum', 'ensemble'), + None, + iris.coords.CellMethod('mean', 'ensemble')]) + def test_unrecognised(self): unrecognised_heading = 'bla else' av_or_int = ['something average', diff --git a/lib/iris/tests/unit/fileformats/name_loaders/test_generate_cubes.py b/lib/iris/tests/unit/fileformats/name_loaders/test__generate_cubes.py similarity index 96% rename from lib/iris/tests/unit/fileformats/name_loaders/test_generate_cubes.py rename to lib/iris/tests/unit/fileformats/name_loaders/test__generate_cubes.py index 209640cb07..8eb1669180 100644 --- a/lib/iris/tests/unit/fileformats/name_loaders/test_generate_cubes.py +++ b/lib/iris/tests/unit/fileformats/name_loaders/test__generate_cubes.py @@ -45,8 +45,8 @@ def test_cell_methods(self): cubes = list(_generate_cubes(header, column_headings, coords, data_arrays, cell_methods)) - cubes[0].assert_has_call(mock.call.add_cell_method('cell_method_1')) - cubes[1].assert_has_call(mock.call.add_cell_method('cell_method_2')) + cubes[0].assert_has_calls([mock.call.add_cell_method('cell_method_1')]) + cubes[1].assert_has_calls([mock.call.add_cell_method('cell_method_2')]) class TestCircularLongitudes(tests.IrisTest): diff --git a/lib/iris/tests/unit/fileformats/pp/test_PPField.py b/lib/iris/tests/unit/fileformats/pp/test_PPField.py index eac35fd124..a078b812dd 100644 --- a/lib/iris/tests/unit/fileformats/pp/test_PPField.py +++ b/lib/iris/tests/unit/fileformats/pp/test_PPField.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2013 - 2014, Met Office +# (C) British Crown Copyright 2013 - 2015, Met Office # # This file is part of Iris. # @@ -95,8 +95,11 @@ def field_checksum(data): with mock.patch('warnings.warn') as warn: checksum_64 = field_checksum(data_64.astype('>f8')) - self.assertEquals(checksum_32, checksum_64) - warn.assert_called() + self.assertEqual(checksum_32, checksum_64) + warn.assert_called_once_with( + 'Downcasting array precision from float64 to float32 for save.' + 'If float64 precision is required then please save in a ' + 'different format') class Test_calendar(tests.IrisTest): diff --git a/lib/iris/unit.py b/lib/iris/unit.py index b5395b5645..ba91f9225f 100644 --- a/lib/iris/unit.py +++ b/lib/iris/unit.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2010 - 2014, Met Office +# (C) British Crown Copyright 2010 - 2015, Met Office # # This file is part of Iris. # @@ -634,7 +634,8 @@ def date2num(date, unit, calendar): unit_string = unit.rstrip(" UTC") if unit_string.endswith(" since epoch"): unit_string = unit_string.replace("epoch", IRIS_EPOCH) - return netcdftime.date2num(date, unit_string, calendar) + cdftime = netcdftime.utime(unit_string, calendar=calendar) + return cdftime.date2num(date) def num2date(time_value, unit, calendar): @@ -700,7 +701,8 @@ def num2date(time_value, unit, calendar): unit_string = unit.rstrip(" UTC") if unit_string.endswith(" since epoch"): unit_string = unit_string.replace("epoch", IRIS_EPOCH) - return netcdftime.num2date(time_value, unit_string, calendar) + cdftime = netcdftime.utime(unit_string, calendar=calendar) + return cdftime.num2date(time_value) def _handler(func):