Skip to content

Commit

Permalink
Replace CubeList init with new. Cube testing duck-type.
Browse files Browse the repository at this point in the history
  • Loading branch information
pp-mo committed May 25, 2022
1 parent 02447b3 commit 69f8920
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 51 deletions.
30 changes: 15 additions & 15 deletions lib/iris/cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,16 +152,13 @@ class CubeList(list):
"""

def __new__(cls, list_of_cubes=None):
"""Given a :class:`list` of cubes, return a CubeList instance."""
cube_list = list.__new__(cls, list_of_cubes)

# Check that all items in the incoming list are cubes.
if not all([isinstance(cube, Cube) for cube in cube_list]):
raise ValueError(
"All items in list_of_cubes must be Cube " "instances."
)
return cube_list
def __init__(self, *args, **kwargs):
"""Given an iterable of cubes, return a CubeList instance."""
# Do whatever a list does, to initialise ourself "as a list"
super().__init__(*args, **kwargs)
# Check that all items in the list are cubes.
for cube in self:
self._assert_is_cube(cube)

def __str__(self):
"""Runs short :meth:`Cube.summary` on every cube."""
Expand All @@ -177,13 +174,16 @@ def __str__(self):

def __repr__(self):
"""Runs repr on every cube."""
return '[%s]' % ',\n'.join([repr(cube) for cube in self])
return "[%s]" % ",\n".join([repr(cube) for cube in self])

@staticmethod
def _assert_is_cube(obj):
if not isinstance(obj, Cube):
msg = ("Object of type '{}' does not belong in a cubelist.")
raise ValueError(msg.format(type(obj).__name__))
if not hasattr(obj, "add_aux_coord"):
msg = (
r"Object {obj} cannot be put in a cubelist, "
"as it is not a Cube."
)
raise ValueError(msg)

# TODO #370 Which operators need overloads?

Expand Down Expand Up @@ -212,7 +212,7 @@ def __iadd__(self, other_cubes):
"""
Add a sequence of cubes to the cubelist in place.
"""
super(CubeList, self).__iadd__(CubeList(other_cubes))
return super(CubeList, self).__iadd__(CubeList(other_cubes))

def __setitem__(self, key, cube_or_sequence):
"""Set self[key] to cube or sequence of cubes"""
Expand Down
65 changes: 29 additions & 36 deletions lib/iris/tests/unit/cube/test_CubeList.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,8 @@
import iris.tests as tests # isort:skip

import collections
from unittest import mock

import copy
from unittest import mock

from cf_units import Unit
import numpy as np
Expand All @@ -25,14 +24,15 @@
from iris.fileformats.pp import STASH
import iris.tests.stock

NOT_CUBE_MSG = "Object of type '{}' does not belong in a cubelist."
NOT_CUBE_MSG = "cannot be put in a cubelist, as it is not a Cube."
NON_ITERABLE_MSG = "object is not iterable"


class Test_append(tests.IrisTest):
def setUp(self):
self.cubelist = iris.cube.CubeList()
self.cube1 = iris.cube.Cube(1, long_name='foo')
self.cube2 = iris.cube.Cube(1, long_name='bar')
self.cube1 = iris.cube.Cube(1, long_name="foo")
self.cube2 = iris.cube.Cube(1, long_name="bar")

def test_pass(self):
self.cubelist.append(self.cube1)
Expand All @@ -41,8 +41,7 @@ def test_pass(self):
self.assertEqual(self.cubelist[-1], self.cube2)

def test_fail(self):
with self.assertRaisesRegexp(ValueError,
NOT_CUBE_MSG.format('NoneType')):
with self.assertRaisesRegex(ValueError, NOT_CUBE_MSG):
self.cubelist.append(None)


Expand Down Expand Up @@ -94,8 +93,8 @@ def test_empty(self):

class Test_extend(tests.IrisTest):
def setUp(self):
self.cube1 = iris.cube.Cube(1, long_name='foo')
self.cube2 = iris.cube.Cube(1, long_name='bar')
self.cube1 = iris.cube.Cube(1, long_name="foo")
self.cube2 = iris.cube.Cube(1, long_name="bar")
self.cubelist1 = iris.cube.CubeList([self.cube1])
self.cubelist2 = iris.cube.CubeList([self.cube2])

Expand All @@ -107,12 +106,11 @@ def test_pass(self):
self.assertEqual(cubelist[-1], self.cube2)

def test_fail(self):
with self.assertRaisesRegexp(TypeError, 'Cube is not iterable'):
with self.assertRaisesRegex(TypeError, NON_ITERABLE_MSG):
self.cubelist1.extend(self.cube1)
msg = "'NoneType' object is not iterable"
with self.assertRaisesRegexp(TypeError, msg):
with self.assertRaisesRegex(TypeError, NON_ITERABLE_MSG):
self.cubelist1.extend(None)
with self.assertRaisesRegexp(ValueError, NOT_CUBE_MSG.format('int')):
with self.assertRaisesRegex(ValueError, NOT_CUBE_MSG):
self.cubelist1.extend(range(3))


Expand Down Expand Up @@ -178,8 +176,8 @@ def test_different_orders(self):

class Test_iadd(tests.IrisTest):
def setUp(self):
self.cube1 = iris.cube.Cube(1, long_name='foo')
self.cube2 = iris.cube.Cube(1, long_name='bar')
self.cube1 = iris.cube.Cube(1, long_name="foo")
self.cube2 = iris.cube.Cube(1, long_name="bar")
self.cubelist1 = iris.cube.CubeList([self.cube1])
self.cubelist2 = iris.cube.CubeList([self.cube2])

Expand All @@ -191,29 +189,26 @@ def test_pass(self):
self.assertEqual(cubelist[-1], self.cube2)

def test_fail(self):
msg = 'Cube is not iterable'
with self.assertRaisesRegexp(TypeError, msg):
with self.assertRaisesRegex(TypeError, NON_ITERABLE_MSG):
self.cubelist1 += self.cube1
msg = "'float' object is not iterable"
with self.assertRaisesRegexp(TypeError, msg):
self.cubelist1 += 1.
with self.assertRaisesRegexp(ValueError, NOT_CUBE_MSG.format('int')):
with self.assertRaisesRegex(TypeError, NON_ITERABLE_MSG):
self.cubelist1 += 1.0
with self.assertRaisesRegex(ValueError, NOT_CUBE_MSG):
self.cubelist1 += range(3)


class Test_insert(tests.IrisTest):
def setUp(self):
self.cube1 = iris.cube.Cube(1, long_name='foo')
self.cube2 = iris.cube.Cube(1, long_name='bar')
self.cube1 = iris.cube.Cube(1, long_name="foo")
self.cube2 = iris.cube.Cube(1, long_name="bar")
self.cubelist = iris.cube.CubeList([self.cube1] * 3)

def test_pass(self):
self.cubelist.insert(1, self.cube2)
self.assertEqual(self.cubelist[1], self.cube2)

def test_fail(self):
with self.assertRaisesRegexp(ValueError,
NOT_CUBE_MSG.format('NoneType')):
with self.assertRaisesRegex(ValueError, NOT_CUBE_MSG):
self.cubelist.insert(0, None)


Expand Down Expand Up @@ -363,9 +358,9 @@ def test_combination_with_extra_triple(self):

class Test_setitem(tests.IrisTest):
def setUp(self):
self.cube1 = iris.cube.Cube(1, long_name='foo')
self.cube2 = iris.cube.Cube(1, long_name='bar')
self.cube3 = iris.cube.Cube(1, long_name='boo')
self.cube1 = iris.cube.Cube(1, long_name="foo")
self.cube2 = iris.cube.Cube(1, long_name="bar")
self.cube3 = iris.cube.Cube(1, long_name="boo")
self.cubelist = iris.cube.CubeList([self.cube1] * 3)

def test_pass(self):
Expand All @@ -374,20 +369,18 @@ def test_pass(self):
self.cubelist[:2] = (self.cube2, self.cube3)
self.assertEqual(
self.cubelist,
iris.cube.CubeList([self.cube2, self.cube3, self.cube1]))
iris.cube.CubeList([self.cube2, self.cube3, self.cube1]),
)

def test_fail(self):
with self.assertRaisesRegexp(ValueError,
NOT_CUBE_MSG.format('NoneType')):
with self.assertRaisesRegex(ValueError, NOT_CUBE_MSG):
self.cubelist[0] = None
with self.assertRaisesRegexp(ValueError,
NOT_CUBE_MSG.format('NoneType')):
with self.assertRaisesRegex(ValueError, NOT_CUBE_MSG):
self.cubelist[0:2] = [self.cube3, None]

msg = "can only assign an iterable"
with self.assertRaisesRegexp(TypeError, msg):
with self.assertRaisesRegex(TypeError, NON_ITERABLE_MSG):
self.cubelist[:1] = 2.5
with self.assertRaisesRegexp(TypeError, msg):
with self.assertRaisesRegex(TypeError, NON_ITERABLE_MSG):
self.cubelist[:1] = self.cube1


Expand Down

0 comments on commit 69f8920

Please sign in to comment.