From d80abb9994510ba9968227767990a2e39f66d452 Mon Sep 17 00:00:00 2001 From: Richard Hattersley Date: Thu, 12 Nov 2015 09:34:19 +0000 Subject: [PATCH] Deprecate legacy_custom_rules --- lib/iris/fileformats/grib/__init__.py | 4 +- lib/iris/fileformats/pp.py | 2 +- lib/iris/fileformats/rules.py | 40 +++++++++- .../test_pp_constrained_load_cubes.py | 6 +- .../unit/fileformats/rules/test_Loader.py | 73 +++++++++++++++++++ 5 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 lib/iris/tests/unit/fileformats/rules/test_Loader.py diff --git a/lib/iris/fileformats/grib/__init__.py b/lib/iris/fileformats/grib/__init__.py index cb1ec91c6f..54f2bdbab0 100644 --- a/lib/iris/fileformats/grib/__init__.py +++ b/lib/iris/fileformats/grib/__init__.py @@ -894,7 +894,7 @@ def load_cubes(filenames, callback=None, auto_regularise=True): grib_loader = iris.fileformats.rules.Loader( _GribMessage.messages_from_filename, {}, - iris.fileformats.grib._load_convert.convert, None) + iris.fileformats.grib._load_convert.convert) else: if auto_regularise is not None: # The old loader supports the auto_regularise keyword, but in @@ -907,7 +907,7 @@ def load_cubes(filenames, callback=None, auto_regularise=True): grib_loader = iris.fileformats.rules.Loader( grib_generator, {'auto_regularise': auto_regularise}, - iris.fileformats.grib.load_rules.convert, None) + iris.fileformats.grib.load_rules.convert) return iris.fileformats.rules.load_cubes(filenames, callback, grib_loader) diff --git a/lib/iris/fileformats/pp.py b/lib/iris/fileformats/pp.py index 7791e295e0..be08eac4fe 100644 --- a/lib/iris/fileformats/pp.py +++ b/lib/iris/fileformats/pp.py @@ -2035,7 +2035,7 @@ def _load_cubes_variable_loader(filenames, callback, loading_function, pp_filter = _convert_constraints(constraints) pp_loader = iris.fileformats.rules.Loader( loading_function, loading_function_kwargs or {}, - iris.fileformats.pp_rules.convert, None) + iris.fileformats.pp_rules.convert) return iris.fileformats.rules.load_cubes(filenames, callback, pp_loader, pp_filter) diff --git a/lib/iris/fileformats/rules.py b/lib/iris/fileformats/rules.py index b5d24af753..e7aa477985 100644 --- a/lib/iris/fileformats/rules.py +++ b/lib/iris/fileformats/rules.py @@ -779,9 +779,41 @@ def _ensure_aligned(regrid_cache, src_cube, target_cube): return result_cube -Loader = collections.namedtuple('Loader', - ('field_generator', 'field_generator_kwargs', - 'converter', 'legacy_custom_rules')) +_loader_attrs = ('field_generator', 'field_generator_kwargs', + 'converter', 'legacy_custom_rules') +class Loader(collections.namedtuple('Loader', _loader_attrs)): + def __new__(cls, field_generator, field_generator_kwargs, converter, + legacy_custom_rules=None): + """ + Create a definition of a field-based Cube loader. + + Args: + + * field_generator + A callable that accepts a filename as its first argument and + returns an iterable of field objects. + + * field_generator_kwargs + Additional arguments to be passed to the field_generator. + + * converter + A callable that converts a field object into a Cube. + + Kwargs: + + * legacy_custom_rules + An object with a callable `verify` attribute with two + parameters: (cube, field). Legacy method for modifying + Cubes during the load process. Default is None. + + .. deprecated:: 1.9 + + """ + if legacy_custom_rules is not None: + warnings.warn('The `legacy_custom_rules` attribute is ' + 'deprecated.') + return tuple.__new__(cls, (field_generator, field_generator_kwargs, + converter, legacy_custom_rules)) ConversionMetadata = collections.namedtuple('ConversionMetadata', @@ -846,6 +878,8 @@ def load_cubes(filenames, user_callback, loader, filter_function=None): # Run any custom user-provided rules. if loader.legacy_custom_rules: + warnings.warn('The `legacy_custom_rules` attribute of ' + 'the `loader` is deprecated.') loader.legacy_custom_rules.verify(cube, field) cube = iris.io.run_callback(user_callback, cube, field, filename) diff --git a/lib/iris/tests/integration/test_pp_constrained_load_cubes.py b/lib/iris/tests/integration/test_pp_constrained_load_cubes.py index 5c8f0c9972..995506d5a3 100644 --- a/lib/iris/tests/integration/test_pp_constrained_load_cubes.py +++ b/lib/iris/tests/integration/test_pp_constrained_load_cubes.py @@ -35,7 +35,7 @@ def test_pp_with_stash_constraint(self): filenames = [tests.get_data_path(('PP', 'globClim1', 'dec_subset.pp'))] stcon = iris.AttributeConstraint(STASH='m01s00i004') pp_constraints = pp._convert_constraints(stcon) - pp_loader = iris.fileformats.rules.Loader(pp.load, {}, convert, None) + pp_loader = iris.fileformats.rules.Loader(pp.load, {}, convert) cubes = list(load_cubes(filenames, None, pp_loader, pp_constraints)) self.assertEqual(len(cubes), 38) @@ -45,7 +45,7 @@ def test_pp_with_stash_constraints(self): stcon1 = iris.AttributeConstraint(STASH='m01s00i004') stcon2 = iris.AttributeConstraint(STASH='m01s00i010') pp_constraints = pp._convert_constraints([stcon1, stcon2]) - pp_loader = iris.fileformats.rules.Loader(pp.load, {}, convert, None) + pp_loader = iris.fileformats.rules.Loader(pp.load, {}, convert) cubes = list(load_cubes(filenames, None, pp_loader, pp_constraints)) self.assertEqual(len(cubes), 76) @@ -53,7 +53,7 @@ def test_pp_with_stash_constraints(self): def test_pp_no_constraint(self): filenames = [tests.get_data_path(('PP', 'globClim1', 'dec_subset.pp'))] pp_constraints = pp._convert_constraints(None) - pp_loader = iris.fileformats.rules.Loader(pp.load, {}, convert, None) + pp_loader = iris.fileformats.rules.Loader(pp.load, {}, convert) cubes = list(load_cubes(filenames, None, pp_loader, pp_constraints)) self.assertEqual(len(cubes), 152) diff --git a/lib/iris/tests/unit/fileformats/rules/test_Loader.py b/lib/iris/tests/unit/fileformats/rules/test_Loader.py new file mode 100644 index 0000000000..63a69b31e9 --- /dev/null +++ b/lib/iris/tests/unit/fileformats/rules/test_Loader.py @@ -0,0 +1,73 @@ +# (C) British Crown Copyright 2015, Met Office +# +# This file is part of Iris. +# +# Iris is free software: you can redistribute it and/or modify it under +# the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Iris is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Iris. If not, see . +"""Unit tests for :class:`iris.fileformats.rules.Loader`.""" + +from __future__ import (absolute_import, division, print_function) +from six.moves import (filter, input, map, range, zip) # noqa + +# Import iris.tests first so that some things can be initialised before +# importing anything else. +import iris.tests as tests + +import mock + +from iris.fileformats.rules import Loader + + +class Test___init__(tests.IrisTest): + def test_normal(self): + with mock.patch('warnings.warn') as warn: + loader = Loader(mock.sentinel.GEN_FUNC, + mock.sentinel.GEN_FUNC_KWARGS, + mock.sentinel.CONVERTER) + self.assertEqual(warn.call_count, 0) + self.assertIs(loader.field_generator, mock.sentinel.GEN_FUNC) + self.assertIs(loader.field_generator_kwargs, + mock.sentinel.GEN_FUNC_KWARGS) + self.assertIs(loader.converter, mock.sentinel.CONVERTER) + self.assertIs(loader.legacy_custom_rules, None) + + def test_normal_with_explicit_none(self): + with mock.patch('warnings.warn') as warn: + loader = Loader(mock.sentinel.GEN_FUNC, + mock.sentinel.GEN_FUNC_KWARGS, + mock.sentinel.CONVERTER, None) + self.assertEqual(warn.call_count, 0) + self.assertIs(loader.field_generator, mock.sentinel.GEN_FUNC) + self.assertIs(loader.field_generator_kwargs, + mock.sentinel.GEN_FUNC_KWARGS) + self.assertIs(loader.converter, mock.sentinel.CONVERTER) + self.assertIs(loader.legacy_custom_rules, None) + + def test_deprecated_custom_rules(self): + with mock.patch('warnings.warn') as warn: + loader = Loader(mock.sentinel.GEN_FUNC, + mock.sentinel.GEN_FUNC_KWARGS, + mock.sentinel.CONVERTER, + mock.sentinel.CUSTOM_RULES) + self.assertEqual(warn.call_count, 1) + self.assertEqual(warn.call_args[0][0], + 'The `legacy_custom_rules` attribute is deprecated.') + self.assertIs(loader.field_generator, mock.sentinel.GEN_FUNC) + self.assertIs(loader.field_generator_kwargs, + mock.sentinel.GEN_FUNC_KWARGS) + self.assertIs(loader.converter, mock.sentinel.CONVERTER) + self.assertIs(loader.legacy_custom_rules, mock.sentinel.CUSTOM_RULES) + + +if __name__ == '__main__': + tests.main()