Skip to content

Commit a2a6015

Browse files
committed
More small cosmetic changes, plus minimal bounds in repr.
1 parent e8bef5f commit a2a6015

File tree

5 files changed

+70
-61
lines changed

5 files changed

+70
-61
lines changed

lib/iris/coords.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ def summary(
282282
convert_dates=True,
283283
):
284284
"""
285-
Make a printable text summary of a :class:.
285+
Make a printable text summary.
286286
287287
Parameters
288288
----------
@@ -446,6 +446,9 @@ def flatten_array_str(array_str):
446446
# "placeholder" representation.
447447
data_str = "[...]"
448448

449+
if self.has_bounds():
450+
data_str += "+bnds"
451+
449452
if self.shape != (1,):
450453
# Anything non-scalar : show shape as well.
451454
data_str += f" shape{shape_str}"

lib/iris/experimental/ugrid/mesh.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,7 @@ def line(text, i_indent=0):
10301030
if optional_conns:
10311031
line("optional connectivities", 1)
10321032
for name, conn in optional_conns.items():
1033-
conn_string = conn.summary(shorten=True, max_array_width=0)
1033+
conn_string = conn.summary(shorten=True, linewidth=0)
10341034
line(f"{name}: {conn_string}", 2)
10351035

10361036
# Output the detail properties, basically those from CFVariableMixin
@@ -2953,31 +2953,22 @@ def summary(self, *args, **kwargs):
29532953
else:
29542954
shorten = kwargs.get("shorten", False)
29552955

2956-
# We need a short one-line printout to identify the mesh, but at
2957-
# present this is tricky, because the Mesh class itself doesn't
2958-
# provide one.
2959-
# So for now we "fake" it, in a rather preliminary way...
2960-
mesh_name = self.mesh.name()
2961-
if mesh_name in (None, "", "unknown"):
2962-
mesh_name = None
2963-
if mesh_name:
2964-
# Use a more human-readable form
2965-
mesh_string = mesh_name
2966-
else:
2967-
# Mimic the generic object.__str__ style.
2968-
mesh_id = id(self.mesh)
2969-
mesh_string = f"<Mesh object at {hex(mesh_id)}>"
2970-
29712956
# Get the default-form result.
29722957
if shorten:
29732958
# NOTE: we simply aren't interested in the values for the repr,
29742959
# so fix linewidth to suppress them
29752960
kwargs["linewidth"] = 1
29762961

29772962
result = super().summary(*args, **kwargs)
2963+
2964+
# Modify the generic 'default-form' result to produce what we want.
29782965
if shorten:
29792966
# Single-line form : insert the mesh+location before the array part
29802967
i_array = result.index("[")
2968+
mesh_string = self.mesh.name()
2969+
if mesh_string == "unknown":
2970+
# If no name, replace with the one-line summary
2971+
mesh_string = self.mesh.summary(shorten=True)
29812972
extra_str = f"mesh({mesh_string}) location({self.location}) "
29822973
result = result[:i_array] + extra_str + result[i_array:]
29832974
# NOTE: this invalidates the original width calculation and may
@@ -2997,7 +2988,8 @@ def summary(self, *args, **kwargs):
29972988
i_namestart = location_line.index("location:")
29982989
indent = location_line[:i_namestart]
29992990
# Construct a suitable 'mesh' line
3000-
mesh_line = f"{indent}mesh: '{mesh_string}'"
2991+
mesh_string = self.mesh.summary(shorten=True)
2992+
mesh_line = f"{indent}mesh: {mesh_string}"
30012993
# Move the 'location' line, putting it and the 'mesh' line
30022994
# immediately after the header
30032995
del lines[i_location]

lib/iris/tests/unit/coords/test__DimensionalMetadata.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def test_names(self):
248248
def test_bounded(self):
249249
result = self.coord_representations(shape=(3,), bounded=True)
250250
expected = [
251-
"<AuxCoord: x / (m) [0., 1., 2.] shape(3,)>",
251+
"<AuxCoord: x / (m) [0., 1., 2.]+bnds shape(3,)>",
252252
"AuxCoord : x / (m)",
253253
" points: [0., 1., 2.]",
254254
" bounds: [",
@@ -360,7 +360,7 @@ def test_lazy_points(self):
360360
def test_lazy_bounds(self):
361361
result = self.coord_representations(lazy_bounds=True)
362362
expected = [
363-
"<AuxCoord: x / (m) [0., 1., 2., 3., 4.] shape(5,)>",
363+
"<AuxCoord: x / (m) [0., 1., 2., 3., 4.]+bnds shape(5,)>",
364364
"AuxCoord : x / (m)",
365365
" points: [0., 1., 2., 3., 4.]",
366366
" bounds: <lazy>",
@@ -386,7 +386,7 @@ def test_lazy_points_and_bounds(self):
386386
def test_scalar(self):
387387
result = self.coord_representations(shape=(1,), bounded=True)
388388
expected = [
389-
"<AuxCoord: x / (m) [0.]>",
389+
"<AuxCoord: x / (m) [0.]+bnds>",
390390
"AuxCoord : x / (m)",
391391
" points: [0.]",
392392
" bounds: [[-10., 10.]]",
@@ -401,7 +401,7 @@ def test_scalar_masked(self):
401401
shape=(1,), bounded=True, masked=True
402402
)
403403
expected = [
404-
"<AuxCoord: x / (m) [--]>",
404+
"<AuxCoord: x / (m) [--]+bnds>",
405405
"AuxCoord : x / (m)",
406406
" points: [--]",
407407
" bounds: [[--, --]]",
@@ -414,7 +414,7 @@ def test_scalar_masked(self):
414414
def test_length_short(self):
415415
result = self.coord_representations(shape=(2,), bounded=True)
416416
expected = [
417-
"<AuxCoord: x / (m) [0., 1.] shape(2,)>",
417+
"<AuxCoord: x / (m) [0., 1.]+bnds shape(2,)>",
418418
"AuxCoord : x / (m)",
419419
" points: [0., 1.]",
420420
" bounds: [",
@@ -430,7 +430,7 @@ def test_length_medium(self):
430430
# Where bounds are truncated, but points not.
431431
result = self.coord_representations(shape=(14,), bounded=True)
432432
expected = [
433-
"<AuxCoord: x / (m) [ 0., 1., ..., 12., 13.] shape(14,)>",
433+
"<AuxCoord: x / (m) [ 0., 1., ..., 12., 13.]+bnds shape(14,)>",
434434
"AuxCoord : x / (m)",
435435
" points: [",
436436
" 0., 1., 2., 3., 4., 5., 6., 7., 8.,",
@@ -451,7 +451,7 @@ def test_length_long(self):
451451
# Completely truncated representations
452452
result = self.coord_representations(shape=(150,), bounded=True)
453453
expected = [
454-
"<AuxCoord: x / (m) [ 0., 1., ..., 148., 149.] shape(150,)>",
454+
"<AuxCoord: x / (m) [ 0., 1., ..., 148., 149.]+bnds shape(150,)>",
455455
"AuxCoord : x / (m)",
456456
" points: [ 0., 1., ..., 148., 149.]",
457457
" bounds: [",
@@ -542,7 +542,7 @@ def test_dates_scalar(self):
542542
def test_dates_bounds(self):
543543
result = self.coord_representations(dates=True, bounded=True)
544544
expected = [
545-
"<AuxCoord: x / (days since 1970-03-5) [...] shape(5,)>",
545+
"<AuxCoord: x / (days since 1970-03-5) [...]+bnds shape(5,)>",
546546
"AuxCoord : x / (days since 1970-03-5, gregorian calendar)",
547547
" points: [",
548548
" 1970-03-05 00:00:00, 1970-03-06 00:00:00,",
@@ -582,7 +582,7 @@ def test_untypical_bounds(self):
582582
coord.bounds = bounds
583583
result = self.repr_str_strings(coord)
584584
expected = [
585-
"<AuxCoord: x / (m) [0., 1., 2., 3., 4.] shape(5,)>",
585+
"<AuxCoord: x / (m) [0., 1., 2., 3., 4.]+bnds shape(5,)>",
586586
"AuxCoord : x / (m)",
587587
" points: [0., 1., 2., 3., 4.]",
588588
" bounds: [",
@@ -733,7 +733,7 @@ def test_climatological(self):
733733
coord = coord[:1] # Just to make it a bit shorter
734734
result = self.repr_str_strings(coord)
735735
expected = [
736-
"<DimCoord: time / (days since 1970-01-01 00:00:00-00) [...]>",
736+
"<DimCoord: time / (days since 1970-01-01 00:00:00-00) [...]+bnds>",
737737
"DimCoord : time / (days since 1970-01-01 00:00:00-00, gregorian calendar)",
738738
" points: [2001-01-10 00:00:00]",
739739
" bounds: [[2001-01-10 00:00:00, 2011-01-10 00:00:00]]",
@@ -897,10 +897,10 @@ def test_meshcoord(self):
897897
(
898898
"<MeshCoord: longitude / (degrees_east) "
899899
"mesh(test_mesh) location(face) "
900-
"[...] shape(3,)>"
900+
"[...]+bnds shape(3,)>"
901901
),
902902
"MeshCoord : longitude / (degrees_east)",
903-
" mesh: 'test_mesh'",
903+
" mesh: <Mesh: 'test_mesh'>",
904904
" location: 'face'",
905905
" points: [3100, 3101, 3102]",
906906
" bounds: [",

lib/iris/tests/unit/experimental/ugrid/mesh/test_Mesh.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -673,6 +673,10 @@ def setUp(self):
673673
}
674674
self.mesh = mesh.Mesh(**self.kwargs)
675675

676+
def test___repr__basic(self):
677+
expected = "<Mesh: 'my_topology_mesh'>"
678+
self.assertEqual(expected, repr(self.mesh))
679+
676680
def test___repr__varname(self):
677681
self.mesh.long_name = None
678682
expected = "<Mesh: 'mesh'>"

lib/iris/tests/unit/experimental/ugrid/mesh/test_MeshCoord.py

Lines changed: 41 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,6 @@ def setUp(self):
269269

270270
def _expected_elements_regexp(
271271
self,
272-
mesh_reprstyle=False,
273272
standard_name="longitude",
274273
long_name="long-name",
275274
attributes=True,
@@ -278,45 +277,56 @@ def _expected_elements_regexp(
278277
):
279278
# Printed name is standard or long -- we don't have a case with neither
280279
coord_name = standard_name or long_name
281-
if mesh_reprstyle:
282-
regexp = f"^<MeshCoord: {coord_name} / .*>$"
283-
else:
284-
# Construct regexp in 'sections'
285-
# NB each consumes upto first non-space in the next line
286-
regexp = f"MeshCoord : {coord_name} / [^\n]+\n *"
287-
regexp += "mesh: 'test_mesh'\n *"
288-
regexp += f"location: '{location}'\n *"
289-
# Now some optional sections : whichever comes first will match
290-
# arbitrary content leading up to it.
291-
matched_any_upto = False
292-
if standard_name:
280+
# Construct regexp in 'sections'
281+
# NB each consumes upto first non-space in the next line
282+
regexp = f"MeshCoord : {coord_name} / [^\n]+\n *"
283+
regexp += r"mesh: \<Mesh: 'test_mesh'>\n *"
284+
regexp += f"location: '{location}'\n *"
285+
# Now some optional sections : whichever comes first will match
286+
# arbitrary content leading up to it.
287+
matched_any_upto = False
288+
if standard_name:
289+
regexp += ".*"
290+
matched_any_upto = True
291+
regexp += f"standard_name: '{standard_name}'\n *"
292+
if long_name:
293+
if not matched_any_upto:
293294
regexp += ".*"
294295
matched_any_upto = True
295-
regexp += f"standard_name: '{standard_name}'\n *"
296-
if long_name:
297-
if not matched_any_upto:
298-
regexp += ".*"
299-
matched_any_upto = True
300-
regexp += f"long_name: '{long_name}'\n *"
301-
if attributes:
302-
# if we expected attributes, they should come next
303-
# TODO: change this when each attribute goes on a new line
304-
if not matched_any_upto:
305-
regexp += ".*"
306-
matched_any_upto = True
307-
regexp += "attributes: {[^}]*}\n *"
308-
# After those items, expect 'axis' next
309-
# N.B. this FAILS if we had attributes when we didn't expect them
310-
regexp += f"axis: '{axis}'$" # N.B. this is always the end
296+
regexp += f"long_name: '{long_name}'\n *"
297+
if attributes:
298+
# if we expected attributes, they should come next
299+
# TODO: change this when each attribute goes on a new line
300+
if not matched_any_upto:
301+
regexp += ".*"
302+
matched_any_upto = True
303+
regexp += "attributes: {[^}]*}\n *"
304+
# After those items, expect 'axis' next
305+
# N.B. this FAILS if we had attributes when we didn't expect them
306+
regexp += f"axis: '{axis}'$" # N.B. this is always the end
311307

312308
# Compile regexp, also allowing matches across newlines
313309
regexp = re.compile(regexp, flags=re.DOTALL)
314310
return regexp
315311

316312
def test_repr(self):
317-
# One simple check for the condensed form.
313+
# A simple check for the condensed form.
314+
result = repr(self.meshcoord)
315+
expected = (
316+
"<MeshCoord: longitude / (degrees_east) "
317+
"mesh(test_mesh) location(face) [...]+bnds shape(3,)>"
318+
)
319+
self.assertEqual(expected, result)
320+
321+
def test_repr__nameless_mesh(self):
322+
# Check what it does when the Mesh doesn't have a name.
323+
self.mesh.long_name = None
324+
assert self.mesh.name() == "unknown"
318325
result = repr(self.meshcoord)
319-
re_expected = self._expected_elements_regexp(mesh_reprstyle=True)
326+
re_expected = (
327+
r".MeshCoord: longitude / \(degrees_east\) "
328+
r"mesh\(.Mesh object at 0x[^>]+.\) location\(face\) "
329+
)
320330
self.assertRegex(result, re_expected)
321331

322332
def test__str__(self):

0 commit comments

Comments
 (0)