Repository: NCAS-CMS/cfdm

Issue:
Field/domain print fails when dimension corodinate has no data
(First reported over at https://github.com/NCAS-CMS/cf-python/issues/326 - see there for full details)

When a field has a construct which can have data, e.g. a coordinate, but that construct doesn't have data, the `str()` representation hits a `ValueError` regarding the lack of data on that construct, e.g:

```python
>>> import cfdm
>>> f = cfdm.example_field(2)
>>> t = f.construct('time')
>>> t.del_data()
<Data(36): [1959-12-16 12:00:00, ..., 1962-11-16 00:00:00]>
>>> print(f)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-3-fc0364975534> in <module>
----> 1 print(f)

~/miniconda3.9/lib/python3.9/site-packages/cfdm/field.py in __str__(self)
    239             string.append(f"Field ancils    : {field_ancils}")
    240 
--> 241         string.append(str(self.domain))
    242 
    243         return "\n".join(string)

~/miniconda3.9/lib/python3.9/site-packages/cfdm/domain.py in __str__(self)
    194                 if construct_data_axes[cid] == (axis_cid,):
    195                     name = dim.identity(default=f"key%{0}")
--> 196                     y = f"{name}({dim.get_data().size})"
    197                     if y != axis_names[axis_cid]:
    198                         y = f"{name}({axis_names[axis_cid]})"

~/miniconda3.9/lib/python3.9/site-packages/cfdm/core/abstract/propertiesdata.py in get_data(self, default, _units, _fill_value)
    290                 return
    291 
--> 292             return self._default(
    293                 default, message=f"{self.__class__.__name__} has no data"
    294             )

~/miniconda3.9/lib/python3.9/site-packages/cfdm/core/abstract/container.py in _default(self, default, message)
    145                 default = type(default)(message)
    146 
--> 147             raise default
    148 
    149         return default

ValueError: DimensionCoordinate has no data

>>>
```

Something sensible should be displayed, instead.

Comments:

Patch:
diff --git a/Changelog.rst b/Changelog.rst
index 0125dce49..01e43ed93 100644
--- a/Changelog.rst
+++ b/Changelog.rst
@@ -1,3 +1,14 @@
+Version 1.9.?.?
+---------------
+
+**2022-0?-??**
+
+* Fixed bug that caused `cf.Domain.__str__` to fail when a dimension
+  coordinate construct does not have data
+  (https://github.com/NCAS-CMS/cfdm/issues/174)
+
+----
+  
 Version 1.9.0.2
 ---------------
 
diff --git a/cfdm/domain.py b/cfdm/domain.py
index 67c0ea9a0..5745f1cb0 100644
--- a/cfdm/domain.py
+++ b/cfdm/domain.py
@@ -187,15 +187,18 @@ class Domain(
 
         x = []
         dimension_coordinates = self.dimension_coordinates(todict=True)
-        for axis_cid in sorted(self.domain_axes(todict=True)):
+        for axis_cid, axis in sorted(self.domain_axes(todict=True).items()):
             for cid, dim in dimension_coordinates.items():
                 if construct_data_axes[cid] == (axis_cid,):
                     name = dim.identity(default=f"key%{0}")
-                    y = f"{name}({dim.get_data().size})"
+                    y = f"{name}({axis.get_size()})"
                     if y != axis_names[axis_cid]:
                         y = f"{name}({axis_names[axis_cid]})"
+
                     if dim.has_data():
                         y += f" = {dim.get_data()}"
+                    else:
+                        y += " = "
 
                     x.append(y)
 
diff --git a/joss/paper.bib b/joss/paper.bib
index 02241916b..f0831c708 100644
--- a/joss/paper.bib
+++ b/joss/paper.bib
@@ -40,10 +40,10 @@
   title = {{{NetCDF Climate}} and {{Forecast}} ({{CF}}) {{Metadata Conventions v1}}.8},
   publisher = {{CF Conventions Committee}},
   author = {{Eaton}, Brian and {Gregory}, Jonathan and {Drach}, Bob and {Taylor}, Karl and {Hankin}, Steve and {Caron}, John and {Signell}, Rich and {Bentley}, Phil and {Rappa}, Greg and {H{\"o}ck}, Heinke and {Pamment}, Alison and {Juckes}, Martin and {Raspaud}, Martin and {Horne}, Randy and {Whiteaker}, Timothy and {Blodgett}, David and {Zender}, Charlie and {Lee}, Daniel},
-  month = feb,
-  year = 2020,
-  urldate = {2020-07-27},
-  url = {http://cfconventions.org/Data/cf-conventions/cf-conventions-1.8/cf-conventions.html},
+  month = sep,
+  year = 2021,
+  urldate = {2020-09-10},
+  url = {http://cfconventions.org/Data/cf-conventions/cf-conventions-1.9/cf-conventions.html},
 }
 
 @software{Hassell2:2020,


Test patch:
diff --git a/cfdm/test/test_Domain.py b/cfdm/test/test_Domain.py
index 624d180b8..bb6836c33 100644
--- a/cfdm/test/test_Domain.py
+++ b/cfdm/test/test_Domain.py
@@ -42,6 +42,13 @@ class DomainTest(unittest.TestCase):
         for title in (None, "title"):
             d.dump(display=False, _title=title)
 
+        # Test when dimension coordinate has no data
+        d = d.copy()
+        t = d.construct("time")
+        t.del_data()
+        self.assertFalse(t.has_data())
+        str(d)
+
     def test_Domain__init__(self):
         """Test the Domain constructor and source keyword."""
         cfdm.Domain(source="qwerty")