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(' tag per cube. + self.assertEqual(len(self.cubes), n_html_elems) + + +if __name__ == '__main__': + tests.main()