Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cubesummary tidy #3988

Merged
merged 5 commits into from
Feb 10, 2021
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 15 additions & 12 deletions lib/iris/_representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"""
Provides objects describing cube summaries.
"""

import numpy as np
import iris.util


Expand Down Expand Up @@ -66,7 +66,11 @@ def _summary_coord_extra(self, cube, coord):
vary.add(key)
break
value = similar_coord.attributes[key]
if attributes.setdefault(key, value) != value:
# Like "if attributes.setdefault(key, value) != value:"
# ..except setdefault fails if values are numpy arrays.
if key not in attributes:
attributes[key] = value
elif not np.all(attributes[key] == value):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like there exists logic in the metadata to handle this kind of comparison:

def _hexdigest(value):

This would handle edge cases differently (dtype, masked arrays etc.)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that really does look like the right way.

vary.add(key)
break
keys = sorted(vary & set(coord.attributes.keys()))
Expand Down Expand Up @@ -132,9 +136,6 @@ def __init__(self, cube, coord):


class Section:
def _init_(self):
self.contents = []

def is_empty(self):
return self.contents == []

Expand Down Expand Up @@ -180,11 +181,13 @@ def __init__(self, title, cell_methods):


class CubeSummary:
"""
This class provides a structure for output representations of an Iris cube.
TODO: use to produce the printout of :meth:`iris.cube.Cube.__str__`.

"""

def __init__(self, cube, shorten=False, name_padding=35):
self.section_indent = 5
self.item_indent = 10
self.extra_indent = 13
self.shorten = shorten
self.header = FullHeader(cube, name_padding)

# Cache the derived coords so we can rely on consistent
Expand Down Expand Up @@ -249,9 +252,9 @@ def add_vector_section(title, contents, iscoord=True):
add_vector_section("Dimension coordinates:", vector_dim_coords)
add_vector_section("Auxiliary coordinates:", vector_aux_coords)
add_vector_section("Derived coordinates:", vector_derived_coords)
add_vector_section("Cell Measures:", vector_cell_measures, False)
add_vector_section("Cell measures:", vector_cell_measures, False)
add_vector_section(
"Ancillary Variables:", vector_ancillary_variables, False
"Ancillary variables:", vector_ancillary_variables, False
)

self.scalar_sections = {}
Expand All @@ -260,7 +263,7 @@ def add_scalar_section(section_class, title, *args):
self.scalar_sections[title] = section_class(title, *args)

add_scalar_section(
ScalarSection, "Scalar Coordinates:", cube, scalar_coords
ScalarSection, "Scalar coordinates:", cube, scalar_coords
)
add_scalar_section(
ScalarCellMeasureSection,
Expand Down
62 changes: 56 additions & 6 deletions lib/iris/tests/unit/representation/test_representation.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ def test_blank_cube(self):
"Dimension coordinates:",
"Auxiliary coordinates:",
"Derived coordinates:",
"Cell Measures:",
"Ancillary Variables:",
"Cell measures:",
"Ancillary variables:",
]
self.assertEqual(
list(rep.vector_sections.keys()), expected_vector_sections
Expand All @@ -66,7 +66,7 @@ def test_blank_cube(self):
self.assertTrue(vector_section.is_empty())

expected_scalar_sections = [
"Scalar Coordinates:",
"Scalar coordinates:",
"Scalar cell measures:",
"Attributes:",
"Cell methods:",
Expand Down Expand Up @@ -111,7 +111,7 @@ def test_scalar_coord(self):
cube.add_aux_coord(scalar_coord_text)
rep = iris._representation.CubeSummary(cube)

scalar_section = rep.scalar_sections["Scalar Coordinates:"]
scalar_section = rep.scalar_sections["Scalar coordinates:"]

self.assertEqual(len(scalar_section.contents), 3)

Expand All @@ -137,7 +137,7 @@ def test_cell_measure(self):
cube.add_cell_measure(cell_measure, 0)
rep = iris._representation.CubeSummary(cube)

cm_section = rep.vector_sections["Cell Measures:"]
cm_section = rep.vector_sections["Cell measures:"]
self.assertEqual(len(cm_section.contents), 1)

cm_summary = cm_section.contents[0]
Expand All @@ -150,7 +150,7 @@ def test_ancillary_variable(self):
cube.add_ancillary_variable(cell_measure, 0)
rep = iris._representation.CubeSummary(cube)

av_section = rep.vector_sections["Ancillary Variables:"]
av_section = rep.vector_sections["Ancillary variables:"]
self.assertEqual(len(av_section.contents), 1)

av_summary = av_section.contents[0]
Expand Down Expand Up @@ -182,6 +182,56 @@ def test_cell_methods(self):
expected_contents = ["mean: x, y", "mean: x"]
self.assertEqual(cell_method_section.contents, expected_contents)

def test_scalar_cube(self):
cube = self.cube
while cube.ndim > 0:
cube = cube[0]
rep = iris._representation.CubeSummary(cube)
self.assertEqual(rep.header.nameunit, "air_temperature / (K)")
self.assertTrue(rep.header.dimension_header.scalar)
self.assertEqual(rep.header.dimension_header.dim_names, [])
self.assertEqual(rep.header.dimension_header.shape, [])
self.assertEqual(rep.header.dimension_header.contents, ["scalar cube"])
self.assertEqual(len(rep.vector_sections), 5)
self.assertTrue(
all(sect.is_empty() for sect in rep.vector_sections.values())
)
self.assertEqual(len(rep.scalar_sections), 4)
self.assertEqual(
len(rep.scalar_sections["Scalar coordinates:"].contents), 1
)
self.assertTrue(
rep.scalar_sections["Scalar cell measures:"].is_empty()
)
self.assertTrue(rep.scalar_sections["Attributes:"].is_empty())
self.assertTrue(rep.scalar_sections["Cell methods:"].is_empty())

def test_coord_attributes(self):
cube = self.cube
co1 = cube.coord("latitude")
co1.attributes.update(dict(a=1, b=2))
co2 = co1.copy()
co2.attributes.update(dict(a=7, z=77))
cube.add_aux_coord(co2, cube.coord_dims(co1))
rep = iris._representation.CubeSummary(cube)
co1_summ = rep.vector_sections["Dimension coordinates:"].contents[0]
co2_summ = rep.vector_sections["Auxiliary coordinates:"].contents[0]
self.assertEqual(co1_summ.extra, "a=1")
self.assertEqual(co2_summ.extra, "a=7, z=77")

def test_array_attributes(self):
cube = self.cube
co1 = cube.coord("latitude")
co1.attributes.update(dict(a=1, array=np.array([1.2, 3])))
co2 = co1.copy()
co2.attributes.update(dict(b=2, array=np.array([3.2, 1])))
cube.add_aux_coord(co2, cube.coord_dims(co1))
rep = iris._representation.CubeSummary(cube)
co1_summ = rep.vector_sections["Dimension coordinates:"].contents[0]
co2_summ = rep.vector_sections["Auxiliary coordinates:"].contents[0]
self.assertEqual(co1_summ.extra, "array=array([1.2, 3. ])")
self.assertEqual(co2_summ.extra, "array=array([3.2, 1. ]), b=2")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the sake of testing numpy array equality, it might also be worth testing the case where two arrays are equal and the case where arrays have different shapes.



if __name__ == "__main__":
tests.main()