From 6ccac61f96db1bae1e70f53ca611e1a3b1d133fe Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 10:23:04 +0100 Subject: [PATCH 01/10] Code changes --- lib/iris/__init__.py | 11 ++++-- lib/iris/fileformats/cf.py | 75 ++++++++++++++++---------------------- 2 files changed, 39 insertions(+), 47 deletions(-) diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index 51f97d2acb..812a921c75 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -143,7 +143,7 @@ def callback(cube, field, filename): class Future(threading.local): """Run-time configuration controller.""" - def __init__(self, cell_datetime_objects=True, netcdf_promote=False, + def __init__(self, cell_datetime_objects=True, netcdf_promote=True, netcdf_no_unlimited=False, clip_latitudes=False): """ A container for run-time options controls. @@ -197,13 +197,18 @@ def __repr__(self): return msg.format(self.cell_datetime_objects, self.netcdf_promote, self.netcdf_no_unlimited, self.clip_latitudes) - deprecated_options = {'cell_datetime_objects': 'warning'} + deprecated_options = {'cell_datetime_objects': 'warning', + 'netcdf_promote': 'error'} def __setattr__(self, name, value): if name in self.deprecated_options: level = self.deprecated_options[name] if level == 'error': - pass + emsg = ("deprecated {prop!r} behaviour has been removed and " + "setting the 'Future' property {prop!r} has been " + "deprecated to be removed in a future release. " + "PLease remove code that sets this property.") + raise AttributeError(emsg.format(prop=name)) else: msg = ("setting the 'Future' property {!r} is deprecated " "and will be removed in a future release. " diff --git a/lib/iris/fileformats/cf.py b/lib/iris/fileformats/cf.py index 2b8544afdd..5cb26bfe60 100644 --- a/lib/iris/fileformats/cf.py +++ b/lib/iris/fileformats/cf.py @@ -1073,42 +1073,38 @@ def _build(cf_variable): _build(cf_variable) # Determine whether there are any formula terms that - # may be promoted to a CFDataVariable. - if iris.FUTURE.netcdf_promote: - # Restrict promotion to only those formula terms - # that are reference surface/phenomenon. - for cf_var in six.itervalues(self.cf_group.formula_terms): - for cf_root, cf_term in six.iteritems(cf_var.cf_terms_by_root): - cf_root_var = self.cf_group[cf_root] - name = cf_root_var.standard_name or cf_root_var.long_name - terms = reference_terms.get(name, []) - if isinstance(terms, six.string_types) or \ - not isinstance(terms, Iterable): - terms = [terms] - cf_var_name = cf_var.cf_name - if cf_term in terms and \ - cf_var_name not in self.cf_group.promoted: - data_var = CFDataVariable(cf_var_name, cf_var.cf_data) - self.cf_group.promoted[cf_var_name] = data_var - _build(data_var) - break - # Promote any ignored variables. - promoted = set() - not_promoted = ignored.difference(promoted) - while not_promoted: - cf_name = not_promoted.pop() - if cf_name not in self.cf_group.data_variables and \ - cf_name not in self.cf_group.promoted: - data_var = CFDataVariable(cf_name, - self.cf_group[cf_name].cf_data) - self.cf_group.promoted[cf_name] = data_var + # may be promoted to a CFDataVariable and restrict promotion to only + # those formula terms that are reference surface/phenomenon. + for cf_var in six.itervalues(self.cf_group.formula_terms): + for cf_root, cf_term in six.iteritems(cf_var.cf_terms_by_root): + cf_root_var = self.cf_group[cf_root] + name = cf_root_var.standard_name or cf_root_var.long_name + terms = reference_terms.get(name, []) + if isinstance(terms, six.string_types) or \ + not isinstance(terms, Iterable): + terms = [terms] + cf_var_name = cf_var.cf_name + if cf_term in terms and \ + cf_var_name not in self.cf_group.promoted: + data_var = CFDataVariable(cf_var_name, cf_var.cf_data) + self.cf_group.promoted[cf_var_name] = data_var _build(data_var) - # Determine whether there are still any ignored variables - # yet to be promoted. - promoted.add(cf_name) - not_promoted = ignored.difference(promoted) - else: - _netcdf_promote_warning() + break + # Promote any ignored variables. + promoted = set() + not_promoted = ignored.difference(promoted) + while not_promoted: + cf_name = not_promoted.pop() + if cf_name not in self.cf_group.data_variables and \ + cf_name not in self.cf_group.promoted: + data_var = CFDataVariable(cf_name, + self.cf_group[cf_name].cf_data) + self.cf_group.promoted[cf_name] = data_var + _build(data_var) + # Determine whether there are still any ignored variables + # yet to be promoted. + promoted.add(cf_name) + not_promoted = ignored.difference(promoted) def _reset(self): @@ -1132,12 +1128,3 @@ def _getncattr(dataset, attr, default=None): except AttributeError: value = default return value - - -def _netcdf_promote_warning(): - msg = ('NetCDF default loading behaviour currently does not expose ' - 'variables which define reference surfaces for dimensionless ' - 'vertical coordinates as independent Cubes. This behaviour is ' - 'deprecated in favour of automatic promotion to Cubes. To switch ' - 'to the new behaviour, set iris.FUTURE.netcdf_promote to True.') - warn_deprecated(msg) From b20ffa76105c3c735ea335d2ba31c0d067ed99e5 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 10:25:57 +0100 Subject: [PATCH 02/10] Quick win pep8 changes in already-modified method --- lib/iris/fileformats/cf.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/iris/fileformats/cf.py b/lib/iris/fileformats/cf.py index 5cb26bfe60..da43230afd 100644 --- a/lib/iris/fileformats/cf.py +++ b/lib/iris/fileformats/cf.py @@ -1008,9 +1008,14 @@ def _build(cf_variable): for variable_type in self._variable_types: # Prevent grid mapping variables being mis-identified as # CF coordinate variables. - ignore = None if issubclass(variable_type, CFGridMappingVariable) else coordinate_names - match = variable_type.identify(self._dataset.variables, ignore=ignore, - target=cf_variable.cf_name, warn=False) + if issubclass(variable_type, CFGridMappingVariable): + ignore = None + else: + ignore = coordinate_names + match = variable_type.identify(self._dataset.variables, + ignore=ignore, + target=cf_variable.cf_name, + warn=False) # Sanity check dimensionality coverage. for cf_name, cf_var in six.iteritems(match): if cf_var.spans(cf_variable): @@ -1030,7 +1035,8 @@ def _build(cf_variable): # Build CF data variable relationships. if isinstance(cf_variable, CFDataVariable): # Add global netCDF attributes. - cf_group.global_attributes.update(self.cf_group.global_attributes) + cf_group.global_attributes.update( + self.cf_group.global_attributes) # Add appropriate "dimensioned" CF coordinate variables. cf_group.update({cf_name: self.cf_group[cf_name] for cf_name in cf_variable.dimensions if cf_name in @@ -1043,7 +1049,8 @@ def _build(cf_variable): # Add appropriate formula terms. for cf_var in six.itervalues(self.cf_group.formula_terms): for cf_root in cf_var.cf_terms_by_root: - if cf_root in cf_group and cf_var.cf_name not in cf_group: + if (cf_root in cf_group and + cf_var.cf_name not in cf_group): # Sanity check dimensionality. if cf_var.spans(cf_variable): cf_group[cf_var.cf_name] = cf_var From 4616a2931d706ec986422b0555cf91c55360ea1c Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 10:29:47 +0100 Subject: [PATCH 03/10] Improve error message --- lib/iris/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index 812a921c75..00c42f6cfb 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -204,10 +204,10 @@ def __setattr__(self, name, value): if name in self.deprecated_options: level = self.deprecated_options[name] if level == 'error': - emsg = ("deprecated {prop!r} behaviour has been removed and " - "setting the 'Future' property {prop!r} has been " - "deprecated to be removed in a future release. " - "PLease remove code that sets this property.") + emsg = ("setting the 'Future' property {prop!r} has been " + "deprecated to be removed in a future release, and " + "deprecated {prop!r} behaviour has been removed. " + "Please remove code that sets this property.") raise AttributeError(emsg.format(prop=name)) else: msg = ("setting the 'Future' property {!r} is deprecated " From 0056b77f3d85715327179f44a6b62107c0d690e3 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 11:12:29 +0100 Subject: [PATCH 04/10] Update tests, add deprecation directive --- lib/iris/__init__.py | 12 +++-- lib/iris/tests/system_test.py | 2 +- .../unit/fileformats/cf/test_CFReader.py | 50 +++++++------------ 3 files changed, 28 insertions(+), 36 deletions(-) diff --git a/lib/iris/__init__.py b/lib/iris/__init__.py index 00c42f6cfb..c35d2dfc9b 100644 --- a/lib/iris/__init__.py +++ b/lib/iris/__init__.py @@ -172,9 +172,15 @@ def __init__(self, cell_datetime_objects=True, netcdf_promote=True, For more details, see :ref:`using-time-constraints`. - The option `netcdf_promote` controls whether the netCDF loader - will expose variables which define reference surfaces for - dimensionless vertical coordinates as independent Cubes. + .. deprecated:: 2.0.0 + + The option `netcdf_promote` is deprecated and will be removed in a + future release and the deprecated code paths this option used to + toggle have been removed. + + The option `netcdf_promote` controlled whether the netCDF loader + exposed variables that defined reference surfaces for + dimensionless vertical coordinates as independent Cubes. The option `netcdf_no_unlimited`, when True, changes the behaviour of the netCDF saver, such that no dimensions are set to diff --git a/lib/iris/tests/system_test.py b/lib/iris/tests/system_test.py index 28d0517b36..f86a0ec98d 100644 --- a/lib/iris/tests/system_test.py +++ b/lib/iris/tests/system_test.py @@ -74,7 +74,7 @@ def system_test_supported_filetypes(self): filetypes = ('.nc', '.pp') if tests.GRIB_AVAILABLE: filetypes += ('.grib2',) - with iris.FUTURE.context(netcdf_no_unlimited=True, netcdf_promote=True): + with iris.FUTURE.context(netcdf_no_unlimited=True): for filetype in filetypes: saved_tmpfile = iris.util.create_temp_filename(suffix=filetype) iris.save(cm, saved_tmpfile) diff --git a/lib/iris/tests/unit/fileformats/cf/test_CFReader.py b/lib/iris/tests/unit/fileformats/cf/test_CFReader.py index 6de593a0c1..9a33f0ee00 100644 --- a/lib/iris/tests/unit/fileformats/cf/test_CFReader.py +++ b/lib/iris/tests/unit/fileformats/cf/test_CFReader.py @@ -249,9 +249,8 @@ def test_associate_formula_terms_with_data_variable(self): self.assertIs(aux_coord_group[name_bnds].cf_data, getattr(self, name_bnds)) - def test_future_promote_reference(self): - with mock.patch('netCDF4.Dataset', return_value=self.dataset), \ - iris.FUTURE.context(netcdf_promote=True): + def test_promote_reference(self): + with mock.patch('netCDF4.Dataset', return_value=self.dataset): cf_group = CFReader('dummy').cf_group self.assertEqual(len(cf_group), len(self.variables)) # Check the number of data variables. @@ -270,44 +269,31 @@ def test_future_promote_reference(self): def test_formula_terms_ignore(self): self.orography.dimensions = ['lat', 'wibble'] - for state in [False, True]: - with mock.patch('netCDF4.Dataset', return_value=self.dataset), \ - iris.FUTURE.context(netcdf_promote=state), \ - mock.patch('warnings.warn') as warn: - cf_group = CFReader('dummy').cf_group - if state: - group = cf_group.promoted - self.assertEqual(list(group.keys()), ['orography']) - self.assertIs(group['orography'].cf_data, self.orography) - self.assertEqual(warn.call_count, 1) - else: - self.assertEqual(len(cf_group.promoted), 0) - self.assertEqual(warn.call_count, 2) + with mock.patch('netCDF4.Dataset', return_value=self.dataset), \ + mock.patch('warnings.warn') as warn: + cf_group = CFReader('dummy').cf_group + group = cf_group.promoted + self.assertEqual(list(group.keys()), ['orography']) + self.assertIs(group['orography'].cf_data, self.orography) + self.assertEqual(warn.call_count, 1) def test_auxiliary_ignore(self): self.x.dimensions = ['lat', 'wibble'] - for state in [False, True]: - with mock.patch('netCDF4.Dataset', return_value=self.dataset), \ - iris.FUTURE.context(netcdf_promote=state), \ - mock.patch('warnings.warn') as warn: - cf_group = CFReader('dummy').cf_group - if state: - promoted = ['x', 'orography'] - group = cf_group.promoted - self.assertEqual(set(group.keys()), set(promoted)) - for name in promoted: - self.assertIs(group[name].cf_data, getattr(self, name)) - self.assertEqual(warn.call_count, 1) - else: - self.assertEqual(len(cf_group.promoted), 0) - self.assertEqual(warn.call_count, 2) + with mock.patch('netCDF4.Dataset', return_value=self.dataset), \ + mock.patch('warnings.warn') as warn: + cf_group = CFReader('dummy').cf_group + promoted = ['x', 'orography'] + group = cf_group.promoted + self.assertEqual(set(group.keys()), set(promoted)) + for name in promoted: + self.assertIs(group[name].cf_data, getattr(self, name)) + self.assertEqual(warn.call_count, 1) def test_promoted_auxiliary_ignore(self): self.wibble = netcdf_variable('wibble', 'lat wibble', np.float) self.variables['wibble'] = self.wibble self.orography.coordinates = 'wibble' with mock.patch('netCDF4.Dataset', return_value=self.dataset), \ - iris.FUTURE.context(netcdf_promote=True), \ mock.patch('warnings.warn') as warn: cf_group = CFReader('dummy').cf_group.promoted promoted = ['wibble', 'orography'] From 55eaeb329dca2dcd2645d68b7933bd0fbbadce16 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 11:29:15 +0100 Subject: [PATCH 05/10] Docs updates --- docs/iris/example_code/General/cross_section.py | 4 ---- docs/iris/example_code/General/custom_aggregation.py | 4 ---- docs/iris/example_code/General/inset_plot.py | 4 +--- docs/iris/example_code/General/orca_projection.py | 4 ---- docs/iris/example_code/General/polynomial_fit.py | 4 ---- docs/iris/example_code/General/projections_and_annotations.py | 4 ---- docs/iris/example_code/General/rotated_pole_mapping.py | 4 ---- docs/iris/example_code/Meteorology/COP_1d_plot.py | 4 ---- docs/iris/example_code/Meteorology/TEC.py | 4 ---- docs/iris/example_code/Meteorology/hovmoller.py | 4 ---- docs/iris/example_code/Oceanography/atlantic_profiles.py | 4 ---- 11 files changed, 1 insertion(+), 43 deletions(-) diff --git a/docs/iris/example_code/General/cross_section.py b/docs/iris/example_code/General/cross_section.py index ab9025ff99..e0d05fb230 100644 --- a/docs/iris/example_code/General/cross_section.py +++ b/docs/iris/example_code/General/cross_section.py @@ -15,10 +15,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load some test data. fname = iris.sample_data_path('hybrid_height.nc') theta = iris.load_cube(fname, 'air_potential_temperature') diff --git a/docs/iris/example_code/General/custom_aggregation.py b/docs/iris/example_code/General/custom_aggregation.py index 9918aae0d6..d8df506469 100644 --- a/docs/iris/example_code/General/custom_aggregation.py +++ b/docs/iris/example_code/General/custom_aggregation.py @@ -65,10 +65,6 @@ def count_spells(data, threshold, axis, spell_length): def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load the whole time-sequence as a single cube. file_path = iris.sample_data_path('E1_north_america.nc') cube = iris.load_cube(file_path) diff --git a/docs/iris/example_code/General/inset_plot.py b/docs/iris/example_code/General/inset_plot.py index 51abee641b..f2ae2d1155 100644 --- a/docs/iris/example_code/General/inset_plot.py +++ b/docs/iris/example_code/General/inset_plot.py @@ -17,9 +17,7 @@ def main(): - # Load the data - with iris.FUTURE.context(netcdf_promote=True): - cube1 = iris.load_cube(iris.sample_data_path('ostia_monthly.nc')) + cube1 = iris.load_cube(iris.sample_data_path('ostia_monthly.nc')) # Slice into cube to retrieve data for the inset map showing the # data region region = cube1[-1, :, :] diff --git a/docs/iris/example_code/General/orca_projection.py b/docs/iris/example_code/General/orca_projection.py index abe5b19c8e..fb44221221 100644 --- a/docs/iris/example_code/General/orca_projection.py +++ b/docs/iris/example_code/General/orca_projection.py @@ -22,10 +22,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load data filepath = iris.sample_data_path('orca2_votemper.nc') cube = iris.load_cube(filepath) diff --git a/docs/iris/example_code/General/polynomial_fit.py b/docs/iris/example_code/General/polynomial_fit.py index 4737e275b9..84f3265dd1 100644 --- a/docs/iris/example_code/General/polynomial_fit.py +++ b/docs/iris/example_code/General/polynomial_fit.py @@ -16,10 +16,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load some test data. fname = iris.sample_data_path('A1B_north_america.nc') cube = iris.load_cube(fname) diff --git a/docs/iris/example_code/General/projections_and_annotations.py b/docs/iris/example_code/General/projections_and_annotations.py index 7d35399cee..b4cb8b1eb7 100644 --- a/docs/iris/example_code/General/projections_and_annotations.py +++ b/docs/iris/example_code/General/projections_and_annotations.py @@ -106,10 +106,6 @@ def make_plot(projection_name, projection_crs): def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Demonstrate with two different display projections. make_plot('Equidistant Cylindrical', ccrs.PlateCarree()) make_plot('North Polar Stereographic', ccrs.NorthPolarStereo()) diff --git a/docs/iris/example_code/General/rotated_pole_mapping.py b/docs/iris/example_code/General/rotated_pole_mapping.py index 6a4b5757f2..e175e6fe74 100644 --- a/docs/iris/example_code/General/rotated_pole_mapping.py +++ b/docs/iris/example_code/General/rotated_pole_mapping.py @@ -21,10 +21,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load some test data. fname = iris.sample_data_path('rotated_pole.nc') air_pressure = iris.load_cube(fname) diff --git a/docs/iris/example_code/Meteorology/COP_1d_plot.py b/docs/iris/example_code/Meteorology/COP_1d_plot.py index 400e90e986..b582836ece 100644 --- a/docs/iris/example_code/Meteorology/COP_1d_plot.py +++ b/docs/iris/example_code/Meteorology/COP_1d_plot.py @@ -36,10 +36,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load data into three Cubes, one for each set of NetCDF files. e1 = iris.load_cube(iris.sample_data_path('E1_north_america.nc')) diff --git a/docs/iris/example_code/Meteorology/TEC.py b/docs/iris/example_code/Meteorology/TEC.py index ed8a337d0a..43f69fcea0 100644 --- a/docs/iris/example_code/Meteorology/TEC.py +++ b/docs/iris/example_code/Meteorology/TEC.py @@ -20,10 +20,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load the "total electron content" cube. filename = iris.sample_data_path('space_weather.nc') cube = iris.load_cube(filename, 'total electron content') diff --git a/docs/iris/example_code/Meteorology/hovmoller.py b/docs/iris/example_code/Meteorology/hovmoller.py index eef0d4be33..5d8b0852ac 100644 --- a/docs/iris/example_code/Meteorology/hovmoller.py +++ b/docs/iris/example_code/Meteorology/hovmoller.py @@ -17,10 +17,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # load a single cube of surface temperature between +/- 5 latitude fname = iris.sample_data_path('ostia_monthly.nc') cube = iris.load_cube(fname, diff --git a/docs/iris/example_code/Oceanography/atlantic_profiles.py b/docs/iris/example_code/Oceanography/atlantic_profiles.py index 3d3f59e8c5..b3d76ea632 100644 --- a/docs/iris/example_code/Oceanography/atlantic_profiles.py +++ b/docs/iris/example_code/Oceanography/atlantic_profiles.py @@ -22,10 +22,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load the gridded temperature and salinity data. fname = iris.sample_data_path('atlantic_profiles.nc') cubes = iris.load(fname) From c110fe6745a9497c8c3481ca73d8bc29ed3c8772 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 11:57:26 +0100 Subject: [PATCH 06/10] Add new behaviour test and whatsnew entry --- .../incompatiblechange_2017-Oct-24_netcdf-promote.txt | 5 +++++ lib/iris/tests/unit/test_Future.py | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 docs/iris/src/whatsnew/contributions_2.0/incompatiblechange_2017-Oct-24_netcdf-promote.txt diff --git a/docs/iris/src/whatsnew/contributions_2.0/incompatiblechange_2017-Oct-24_netcdf-promote.txt b/docs/iris/src/whatsnew/contributions_2.0/incompatiblechange_2017-Oct-24_netcdf-promote.txt new file mode 100644 index 0000000000..c277df8e2a --- /dev/null +++ b/docs/iris/src/whatsnew/contributions_2.0/incompatiblechange_2017-Oct-24_netcdf-promote.txt @@ -0,0 +1,5 @@ +* Deprecated FUTURE flag :attr:`iris.Future.netcdf_promote`. + +* Removed deprecated behaviour that does not automatically promote NetCDF variables to cubes. + This change means that NetCDF variables that define reference surfaces for dimensionless vertical coordinates + will always be promoted and loaded as independent cubes. \ No newline at end of file diff --git a/lib/iris/tests/unit/test_Future.py b/lib/iris/tests/unit/test_Future.py index aae0687706..c9b8ab9c4c 100644 --- a/lib/iris/tests/unit/test_Future.py +++ b/lib/iris/tests/unit/test_Future.py @@ -47,6 +47,14 @@ def test_invalid_attribute(self): with self.assertRaises(AttributeError): future.numberwang = 7 + def test_invalid_netcdf_promote_attributes(self): + future = Future() + states = [True, False] + exp_emsg = '' + for state in states: + with self.assertRaisesRegexp(AttributeError, exp_emsg): + future.netcdf_promote = state + def test_cell_datetime_objects(self): future = Future() new_value = not future.cell_datetime_objects From 4bae9e21a74e5557859897a1a2a5d9643024fa9c Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 12:22:02 +0100 Subject: [PATCH 07/10] Update license header --- lib/iris/tests/unit/fileformats/cf/test_CFReader.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/iris/tests/unit/fileformats/cf/test_CFReader.py b/lib/iris/tests/unit/fileformats/cf/test_CFReader.py index 9a33f0ee00..033e5ae1f8 100644 --- a/lib/iris/tests/unit/fileformats/cf/test_CFReader.py +++ b/lib/iris/tests/unit/fileformats/cf/test_CFReader.py @@ -1,4 +1,4 @@ -# (C) British Crown Copyright 2014 - 2015, Met Office +# (C) British Crown Copyright 2014 - 2017, Met Office # # This file is part of Iris. # From 71bb231dfe01e14fad0893c39a58e8681dc662c8 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 14:09:04 +0100 Subject: [PATCH 08/10] Correct failing doc/example tests --- docs/iris/example_code/General/SOI_filtering.py | 4 ---- docs/iris/example_code/General/anomaly_log_colouring.py | 4 ---- docs/iris/src/userguide/interpolation_and_regridding.rst | 4 +++- docs/iris/src/userguide/real_and_lazy_data.rst | 3 ++- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/docs/iris/example_code/General/SOI_filtering.py b/docs/iris/example_code/General/SOI_filtering.py index 4d692811e6..a488b5865e 100644 --- a/docs/iris/example_code/General/SOI_filtering.py +++ b/docs/iris/example_code/General/SOI_filtering.py @@ -52,10 +52,6 @@ def low_pass_weights(window, cutoff): def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load the monthly-valued Southern Oscillation Index (SOI) time-series. fname = iris.sample_data_path('SOI_Darwin.nc') soi = iris.load_cube(fname) diff --git a/docs/iris/example_code/General/anomaly_log_colouring.py b/docs/iris/example_code/General/anomaly_log_colouring.py index 72893f3512..d3f71b6ddc 100644 --- a/docs/iris/example_code/General/anomaly_log_colouring.py +++ b/docs/iris/example_code/General/anomaly_log_colouring.py @@ -36,10 +36,6 @@ def main(): - # Enable a future option, to ensure that the netcdf load works the same way - # as in future Iris versions. - iris.FUTURE.netcdf_promote = True - # Load a sample air temperatures sequence. file_path = iris.sample_data_path('E1_north_america.nc') temperatures = iris.load_cube(file_path) diff --git a/docs/iris/src/userguide/interpolation_and_regridding.rst b/docs/iris/src/userguide/interpolation_and_regridding.rst index 13b1f2dace..1ab20d8f30 100644 --- a/docs/iris/src/userguide/interpolation_and_regridding.rst +++ b/docs/iris/src/userguide/interpolation_and_regridding.rst @@ -123,7 +123,9 @@ For instance, the :class:`iris.analysis.Linear` scheme requires 1D numeric, monotonic, coordinates. Supposing we have a single column cube such as the one defined below: - >>> column = iris.load_cube(iris.sample_data_path('hybrid_height.nc'))[:, 0, 0] + >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc'), + 'air_potential_temperature') + >>> column = cube[:, 0, 0] >>> print(column.summary(shorten=True)) air_potential_temperature / (K) (model_level_number: 15) diff --git a/docs/iris/src/userguide/real_and_lazy_data.rst b/docs/iris/src/userguide/real_and_lazy_data.rst index 5391bcff85..fd9070288c 100644 --- a/docs/iris/src/userguide/real_and_lazy_data.rst +++ b/docs/iris/src/userguide/real_and_lazy_data.rst @@ -186,7 +186,8 @@ coordinates' lazy points and bounds: .. doctest:: - >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc')) + >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc'), + 'air_potential_temperature') >>> dim_coord = cube.coord('model_level_number') >>> print(dim_coord.has_lazy_points()) From f1d547990accf01be80906348ce894a0a0ed01b4 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 14:57:22 +0100 Subject: [PATCH 09/10] Correct failing tests --- lib/iris/tests/integration/test_cube.py | 2 +- lib/iris/tests/integration/test_netcdf.py | 9 +++++---- lib/iris/tests/test_cf.py | 2 +- lib/iris/tests/test_netcdf.py | 9 ++++++--- lib/iris/tests/test_plot.py | 2 +- lib/iris/tests/unit/aux_factory/test_AuxCoordFactory.py | 6 +++--- 6 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/iris/tests/integration/test_cube.py b/lib/iris/tests/integration/test_cube.py index 1c34f53605..9b80dfee01 100644 --- a/lib/iris/tests/integration/test_cube.py +++ b/lib/iris/tests/integration/test_cube.py @@ -34,7 +34,7 @@ class Test_aggregated_by(tests.IrisTest): def test_agg_by_aux_coord(self): problem_test_file = tests.get_data_path(('NetCDF', 'testing', 'small_theta_colpex.nc')) - cube = iris.load_cube(problem_test_file) + cube = iris.load_cube(problem_test_file, 'air_potential_temperature') # Test aggregating by aux coord, notably the `forecast_period` aux # coord on `cube`, whose `_points` attribute is a lazy array. diff --git a/lib/iris/tests/integration/test_netcdf.py b/lib/iris/tests/integration/test_netcdf.py index c3f25b3127..fcab14d973 100644 --- a/lib/iris/tests/integration/test_netcdf.py +++ b/lib/iris/tests/integration/test_netcdf.py @@ -74,9 +74,10 @@ def test_save_load_loop(self): with self.temp_filename(suffix='.nc') as filename, \ self.temp_filename(suffix='.nc') as other_filename: iris.save(self.cube, filename) - cube = iris.load_cube(filename) + cube = iris.load_cube(filename, 'air_potential_temperature') iris.save(cube, other_filename) - other_cube = iris.load_cube(other_filename) + other_cube = iris.load_cube(other_filename, + 'air_potential_temperature') self.assertEqual(cube, other_cube) @@ -120,7 +121,7 @@ def test_hybrid_height_cubes(self): sa.points = sa.points * 10 with self.temp_filename('.nc') as fname: iris.save([hh1, hh2], fname) - cubes = iris.load(fname) + cubes = iris.load(fname, 'air_temperature') cubes = sorted(cubes, key=lambda cube: cube.attributes['cube']) self.assertCML(cubes) @@ -203,7 +204,7 @@ class TestLazySave(tests.IrisTest): def test_lazy_preserved_save(self): fpath = tests.get_data_path(('NetCDF', 'label_and_climate', 'small_FC_167_mon_19601101.nc')) - acube = iris.load_cube(fpath) + acube = iris.load_cube(fpath, 'air_temperature') self.assertTrue(acube.has_lazy_data()) with self.temp_filename('.nc') as nc_path: with Saver(nc_path, 'NETCDF4') as saver: diff --git a/lib/iris/tests/test_cf.py b/lib/iris/tests/test_cf.py index 3623367c42..846fe0f829 100644 --- a/lib/iris/tests/test_cf.py +++ b/lib/iris/tests/test_cf.py @@ -254,7 +254,7 @@ def test_attributes_contain_positive(self): def test_attributes_populated(self): filename = tests.get_data_path( ('NetCDF', 'label_and_climate', 'small_FC_167_mon_19601101.nc')) - cube = iris.load_cube(filename) + cube = iris.load_cube(filename, 'air_temperature') self.assertEqual( sorted(cube.coord('longitude').attributes.items()), [('data_type', 'float'), diff --git a/lib/iris/tests/test_netcdf.py b/lib/iris/tests/test_netcdf.py index 6823ef9cf9..4f783c7f0d 100644 --- a/lib/iris/tests/test_netcdf.py +++ b/lib/iris/tests/test_netcdf.py @@ -564,9 +564,10 @@ def test_netcdf_hybrid_height(self): # Test saving a CF-netCDF file which contains a hybrid height # (i.e. dimensionless vertical) coordinate. # Read PP input file. + names = ['air_potential_temperature', 'surface_altitude'] file_in = tests.get_data_path( ('PP', 'COLPEX', 'small_colpex_theta_p_alt.pp')) - cube = iris.load_cube(file_in, 'air_potential_temperature') + cube = iris.load_cube(file_in, names[0]) # Write Cube to netCDF file. with self.temp_filename(suffix='.nc') as file_out: @@ -577,10 +578,12 @@ def test_netcdf_hybrid_height(self): ('netcdf', 'netcdf_save_hybrid_height.cdl')) # Read netCDF file. - cube = iris.load_cube(file_out) + cubes = iris.load(file_out) + cubes_names = [c.name() for c in cubes] + self.assertEqual(cubes_names, names) # Check the PP read, netCDF write, netCDF read mechanism. - self.assertCML(cube, + self.assertCML(cubes.extract(names[0])[0], ('netcdf', 'netcdf_save_load_hybrid_height.cml')) @tests.skip_data diff --git a/lib/iris/tests/test_plot.py b/lib/iris/tests/test_plot.py index 961d5a520e..dcb3622e5d 100644 --- a/lib/iris/tests/test_plot.py +++ b/lib/iris/tests/test_plot.py @@ -348,7 +348,7 @@ def test_1d_positive_down(self): def test_2d_positive_up(self): path = tests.get_data_path(('NetCDF', 'testing', 'small_theta_colpex.nc')) - cube = iris.load_cube(path)[0, :, 42, :] + cube = iris.load_cube(path, 'air_potential_temperature')[0, :, 42, :] qplt.pcolormesh(cube) self.check_graphic() diff --git a/lib/iris/tests/unit/aux_factory/test_AuxCoordFactory.py b/lib/iris/tests/unit/aux_factory/test_AuxCoordFactory.py index 8c44c86f1e..83d10e307f 100644 --- a/lib/iris/tests/unit/aux_factory/test_AuxCoordFactory.py +++ b/lib/iris/tests/unit/aux_factory/test_AuxCoordFactory.py @@ -154,9 +154,9 @@ def test_lazy_complex(self): @tests.skip_data class Test_lazy_aux_coords(tests.IrisTest): def setUp(self): - self.cube = iris.load_cube(tests.get_data_path - (['NetCDF', 'testing', - 'small_theta_colpex.nc'])) + path = tests.get_data_path(['NetCDF', 'testing', + 'small_theta_colpex.nc']) + self.cube = iris.load_cube(path, 'air_potential_temperature') def _check_lazy(self): coords = self.cube.aux_coords + self.cube.derived_coords From b61be2f86f91ea16f9f448900fd977f6322ce046 Mon Sep 17 00:00:00 2001 From: Peter Killick Date: Tue, 24 Oct 2017 16:46:29 +0100 Subject: [PATCH 10/10] Doctest changes --- docs/iris/src/userguide/interpolation_and_regridding.rst | 3 +-- docs/iris/src/userguide/real_and_lazy_data.rst | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/docs/iris/src/userguide/interpolation_and_regridding.rst b/docs/iris/src/userguide/interpolation_and_regridding.rst index 1ab20d8f30..ff35777303 100644 --- a/docs/iris/src/userguide/interpolation_and_regridding.rst +++ b/docs/iris/src/userguide/interpolation_and_regridding.rst @@ -123,8 +123,7 @@ For instance, the :class:`iris.analysis.Linear` scheme requires 1D numeric, monotonic, coordinates. Supposing we have a single column cube such as the one defined below: - >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc'), - 'air_potential_temperature') + >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc'), 'air_potential_temperature') >>> column = cube[:, 0, 0] >>> print(column.summary(shorten=True)) air_potential_temperature / (K) (model_level_number: 15) diff --git a/docs/iris/src/userguide/real_and_lazy_data.rst b/docs/iris/src/userguide/real_and_lazy_data.rst index fd9070288c..3db6125cf8 100644 --- a/docs/iris/src/userguide/real_and_lazy_data.rst +++ b/docs/iris/src/userguide/real_and_lazy_data.rst @@ -186,8 +186,7 @@ coordinates' lazy points and bounds: .. doctest:: - >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc'), - 'air_potential_temperature') + >>> cube = iris.load_cube(iris.sample_data_path('hybrid_height.nc'), 'air_potential_temperature') >>> dim_coord = cube.coord('model_level_number') >>> print(dim_coord.has_lazy_points())