From 0ef6db604376591f3b108f930f732b684502763c Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Thu, 7 Nov 2019 17:17:42 +0000 Subject: [PATCH 1/5] make Coord abstract --- lib/iris/coords.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/iris/coords.py b/lib/iris/coords.py index 050a6cdaad..aaada6d557 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -8,7 +8,7 @@ """ -from abc import ABCMeta +from abc import ABCMeta, abstractmethod from collections import namedtuple from collections.abc import Iterator import copy @@ -1282,6 +1282,7 @@ class Coord(_DimensionalMetadata): """ + @abstractmethod def __init__( self, points, @@ -2565,6 +2566,8 @@ class AuxCoord(Coord): """ + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) # Logically, :class:`Coord` is an abstract class and all actual coords must # be members of some concrete subclass, i.e. an :class:`AuxCoord` or # a :class:`DimCoord`. From 578d0b982d7ae201ca2122a6b6e52211c30ffc42 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Fri, 8 Nov 2019 10:36:58 +0000 Subject: [PATCH 2/5] Fix tests --- lib/iris/tests/unit/coords/test_CellMethod.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/iris/tests/unit/coords/test_CellMethod.py b/lib/iris/tests/unit/coords/test_CellMethod.py index da35d76096..88906dd905 100644 --- a/lib/iris/tests/unit/coords/test_CellMethod.py +++ b/lib/iris/tests/unit/coords/test_CellMethod.py @@ -12,7 +12,7 @@ import iris.tests as tests from iris._cube_coord_common import CFVariableMixin -from iris.coords import CellMethod, Coord +from iris.coords import CellMethod, AuxCoord class Test(tests.IrisTest): @@ -27,38 +27,38 @@ def _check(self, token, coord, default=False): def test_coord_standard_name(self): token = "air_temperature" - coord = Coord(1, standard_name=token) + coord = AuxCoord(1, standard_name=token) self._check(token, coord) def test_coord_long_name(self): token = "long_name" - coord = Coord(1, long_name=token) + coord = AuxCoord(1, long_name=token) self._check(token, coord) def test_coord_long_name_default(self): token = "long name" # includes space - coord = Coord(1, long_name=token) + coord = AuxCoord(1, long_name=token) self._check(token, coord, default=True) def test_coord_var_name(self): token = "var_name" - coord = Coord(1, var_name=token) + coord = AuxCoord(1, var_name=token) self._check(token, coord) def test_coord_var_name_fail(self): token = "var name" # includes space emsg = "is not a valid NetCDF variable name" with self.assertRaisesRegex(ValueError, emsg): - Coord(1, var_name=token) + AuxCoord(1, var_name=token) def test_coord_stash(self): token = "stash" - coord = Coord(1, attributes=dict(STASH=token)) + coord = AuxCoord(1, attributes=dict(STASH=token)) self._check(token, coord) def test_coord_stash_default(self): token = "_stash" # includes leading underscore - coord = Coord(1, attributes=dict(STASH=token)) + coord = AuxCoord(1, attributes=dict(STASH=token)) self._check(token, coord, default=True) def test_string(self): @@ -75,14 +75,14 @@ def test_string_default(self): def test_mixture(self): token = "air_temperature" - coord = Coord(1, standard_name=token) + coord = AuxCoord(1, standard_name=token) result = CellMethod(self.method, coords=[coord, token]) expected = "{}: {}, {}".format(self.method, token, token) self.assertEqual(str(result), expected) def test_mixture_default(self): token = "air temperature" # includes space - coord = Coord(1, long_name=token) + coord = AuxCoord(1, long_name=token) result = CellMethod(self.method, coords=[coord, token]) expected = "{}: unknown, unknown".format(self.method, token, token) self.assertEqual(str(result), expected) From c0be3702de9976721f1bdd8886610fbc53f33ffb Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Fri, 8 Nov 2019 10:50:02 +0000 Subject: [PATCH 3/5] Add test --- lib/iris/tests/unit/coords/test_Coord.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/iris/tests/unit/coords/test_Coord.py b/lib/iris/tests/unit/coords/test_Coord.py index b23b6daa8c..777ab98793 100644 --- a/lib/iris/tests/unit/coords/test_Coord.py +++ b/lib/iris/tests/unit/coords/test_Coord.py @@ -1010,5 +1010,13 @@ def test_remove_bounds(self): self.assertFalse(coord.climatological) +class Test_Coord_is_abstract(tests.IrisTest): + def test_instantiate_fail(self): + emsg = ("Can't instantiate abstract class Coord with abstract" + " methods __init__") + with self.assertRaisesRegex(TypeError, emsg): + _ = Coord(points=[0, 1]) + + if __name__ == "__main__": tests.main() From 9ed21fe02f92a018c71cf58ffb7562cab3804e41 Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 12 Nov 2019 09:41:45 +0000 Subject: [PATCH 4/5] conserve __init__ docstring --- lib/iris/coords.py | 2 ++ lib/iris/tests/unit/coords/test_Coord.py | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/iris/coords.py b/lib/iris/coords.py index aaada6d557..bb2155a77e 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -2567,7 +2567,9 @@ class AuxCoord(Coord): """ def __init__(self, *args, **kwargs): + self.__doc__ = super().__init__.__doc__ super().__init__(*args, **kwargs) + # Logically, :class:`Coord` is an abstract class and all actual coords must # be members of some concrete subclass, i.e. an :class:`AuxCoord` or # a :class:`DimCoord`. diff --git a/lib/iris/tests/unit/coords/test_Coord.py b/lib/iris/tests/unit/coords/test_Coord.py index 777ab98793..ac8a89bcd5 100644 --- a/lib/iris/tests/unit/coords/test_Coord.py +++ b/lib/iris/tests/unit/coords/test_Coord.py @@ -1012,8 +1012,10 @@ def test_remove_bounds(self): class Test_Coord_is_abstract(tests.IrisTest): def test_instantiate_fail(self): - emsg = ("Can't instantiate abstract class Coord with abstract" - " methods __init__") + emsg = ( + "Can't instantiate abstract class Coord with abstract" + " methods __init__" + ) with self.assertRaisesRegex(TypeError, emsg): _ = Coord(points=[0, 1]) From 51889948135dd511900f72ec42d329ee618dd72e Mon Sep 17 00:00:00 2001 From: "stephen.worsley" Date: Tue, 12 Nov 2019 14:05:14 +0000 Subject: [PATCH 5/5] conserve __init__ docstring with wraps --- lib/iris/coords.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/iris/coords.py b/lib/iris/coords.py index bb2155a77e..c5af246166 100644 --- a/lib/iris/coords.py +++ b/lib/iris/coords.py @@ -12,6 +12,7 @@ from collections import namedtuple from collections.abc import Iterator import copy +from functools import wraps from itertools import chain, zip_longest import operator import warnings @@ -2566,8 +2567,8 @@ class AuxCoord(Coord): """ + @wraps(Coord.__init__, assigned=("__doc__",), updated=()) def __init__(self, *args, **kwargs): - self.__doc__ = super().__init__.__doc__ super().__init__(*args, **kwargs) # Logically, :class:`Coord` is an abstract class and all actual coords must