diff --git a/lib/iris/cube.py b/lib/iris/cube.py
index 137aa68586..e13df8220c 100644
--- a/lib/iris/cube.py
+++ b/lib/iris/cube.py
@@ -231,6 +231,11 @@ def __repr__(self):
"""Runs repr on every cube."""
return '[%s]' % ',\n'.join([repr(cube) for cube in self])
+ def _repr_html_(self):
+ from iris.experimental.representation import CubeListRepresentation
+ representer = CubeListRepresentation(self)
+ return representer.repr_html()
+
# TODO #370 Which operators need overloads?
def __add__(self, other):
return CubeList(list.__add__(self, other))
diff --git a/lib/iris/experimental/representation.py b/lib/iris/experimental/representation.py
index 5adef1f06e..b16d79d5de 100644
--- a/lib/iris/experimental/representation.py
+++ b/lib/iris/experimental/representation.py
@@ -1,4 +1,4 @@
-# (C) British Crown Copyright 2018, Met Office
+# (C) British Crown Copyright 2018 - 2019, Met Office
#
# This file is part of Iris.
#
@@ -306,3 +306,89 @@ def repr_html(self):
id=self.cube_id,
shape=shape,
content=content)
+
+
+class CubeListRepresentation(object):
+ _template = """
+
+
+{contents}
+ """
+
+ _accordian_panel = """
+
+
+
{content}
+
+ """
+
+ def __init__(self, cubelist):
+ self.cubelist = cubelist
+ self.cubelist_id = id(self.cubelist)
+
+ def make_content(self):
+ html = []
+ for i, cube in enumerate(self.cubelist):
+ title = '{i}: {summary}'.format(i=i,
+ summary=cube.summary(shorten=True))
+ content = cube._repr_html_()
+ html.append(self._accordian_panel.format(uid=self.cubelist_id,
+ title=title,
+ content=content))
+ return html
+
+ def repr_html(self):
+ contents = self.make_content()
+ contents_str = '\n'.join(contents)
+ return self._template.format(uid=self.cubelist_id,
+ contents=contents_str)
diff --git a/lib/iris/tests/unit/experimental/representation/test_CubeListRepresentation.py b/lib/iris/tests/unit/experimental/representation/test_CubeListRepresentation.py
new file mode 100644
index 0000000000..a9cf07ef9b
--- /dev/null
+++ b/lib/iris/tests/unit/experimental/representation/test_CubeListRepresentation.py
@@ -0,0 +1,83 @@
+# (C) British Crown Copyright 2019, 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 the `iris.cube.CubeRepresentation` class."""
+
+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
+
+from iris.cube import CubeList
+import iris.tests.stock as stock
+
+from iris.experimental.representation import CubeListRepresentation
+
+
+@tests.skip_data
+class Test__instantiation(tests.IrisTest):
+ def setUp(self):
+ self.cubes = CubeList([stock.simple_3d()])
+ self.representer = CubeListRepresentation(self.cubes)
+
+ def test_ids(self):
+ self.assertEqual(id(self.cubes), self.representer.cubelist_id)
+
+
+@tests.skip_data
+class Test_make_content(tests.IrisTest):
+ def setUp(self):
+ self.cubes = CubeList([stock.simple_3d(),
+ stock.lat_lon_cube()])
+ self.representer = CubeListRepresentation(self.cubes)
+ self.content = self.representer.make_content()
+
+ def test_repr_len(self):
+ self.assertEqual(len(self.cubes), len(self.content))
+
+ def test_summary_lines(self):
+ names = [c.name() for c in self.cubes]
+ for name, content in zip(names, self.content):
+ self.assertIn(name, content)
+
+ def test__cube_name_summary_consistency(self):
+ # Just check the first cube in the CubeList.
+ single_cube_html = self.content[0]
+ first_contents_line = single_cube_html.split('\n')[1]
+ # Get the cube name out of the repr html...
+ cube_name = first_contents_line.split('>0: ')[1].split('/')[0]
+ # ... and prettify it (to be the same as in the following cube repr).
+ pretty_cube_name = cube_name.strip().replace('_', ' ').title()
+ self.assertIn(pretty_cube_name, single_cube_html)
+
+
+@tests.skip_data
+class Test_repr_html(tests.IrisTest):
+ def setUp(self):
+ self.cubes = CubeList([stock.simple_3d(),
+ stock.lat_lon_cube()])
+ self.representer = CubeListRepresentation(self.cubes)
+
+ def test_html_length(self):
+ html = self.representer.repr_html()
+ n_html_elems = html.count('