Repository: pydap/pydap

Issue:
Malformed DAS when missing data
I found a dataset which had a missing integer variable, and the resulting DAS contained a syntax error (see https://github.com/Unidata/netcdf4-python/issues/923 for my original report). This is the problematic line:

```
...
    VPED {
        ...
        Int32 WMO_code ;
    }
...
```

Comparing the output with Hyrax (see also https://github.com/OPENDAP/hyrax-docker/issues/6) it seems that Hyrax decides not to yield the line:

```diff
--- das_bad.txt	2019-05-04 13:06:06.779700399 +0200
+++ das_ok.txt	2019-05-04 13:04:13.721630474 +0200
@@ -1,19 +1,18 @@
     VPED {
         String long_name "Wave principal direction at spectral peak";
         String units "degree";
-        Float32 add_offset 180;
-        Float32 scale_factor 0.01;
+        Float32 add_offset 180.000000;
+        Float32 scale_factor 0.00999999978;
         Int16 _FillValue -32767;
         String standard_name "sea_surface_wave_from_direction_at_variance_spectral_density_maximum";
         String cell_methods "time:point area:mean";
         String type_of_analysis "spectral analysis";
-        Int32 WMO_code ;
     }
     VTM02 {
         String long_name "Spectral moments (0,2) wave period (Tm02)";
         String units "s";
-        Float32 add_offset 0;
-        Float32 scale_factor 0.01;
+        Float32 add_offset 0.00000000;
+        Float32 scale_factor 0.00999999978;
         Int16 _FillValue -32767;
         String standard_name "sea_surface_wave_mean_period_from_variance_spectral_density_second_frequency_moment";
         String cell_methods "time:point area:mean";
```

It turns out one single bad attribute invalidates all the DAS and netCDF4 cannot read the properties, in this case screwing up the decoding of the dates. Therefore, it might make sense to catch this type of situation and remove the faulty line.

Discussion:
Juanlu001: Ping @tomkralidis :) I found another potential issue but I'd prefer to submit the PRs one by one...!

Patch:
diff --git a/src/pydap/responses/das.py b/src/pydap/responses/das.py
index 1b18516..43a2ecc 100644
--- a/src/pydap/responses/das.py
+++ b/src/pydap/responses/das.py
@@ -16,6 +16,8 @@ from collections import Iterable
 from six import string_types, integer_types
 from six.moves import map
 
+import numpy as np
+
 from ..model import (DatasetType, BaseType,
                      StructureType, SequenceType,
                      GridType)
@@ -88,8 +90,9 @@ def _basetypegridtype(var, level=0):
 
     for attr in sorted(var.attributes.keys()):
         values = var.attributes[attr]
-        for line in build_attributes(attr, values, level+1):
-            yield line
+        if np.asarray(values).size > 0:
+            for line in build_attributes(attr, values, level+1):
+                yield line
     yield '{indent}}}\n'.format(indent=level*INDENT)
 
 


Test patch:
diff --git a/src/pydap/tests/datasets.py b/src/pydap/tests/datasets.py
index 4e9be1e..b907630 100644
--- a/src/pydap/tests/datasets.py
+++ b/src/pydap/tests/datasets.py
@@ -179,3 +179,15 @@ SimpleGrid["x"] = SimpleGrid["SimpleGrid"]["x"] = BaseType(
     "x", np.arange(3), axis="X", units="degrees_east")
 SimpleGrid["y"] = SimpleGrid["SimpleGrid"]["y"] = BaseType(
     "y", np.arange(2), axis="Y", units="degrees_north")
+
+
+# a faulty grid
+FaultyGrid = DatasetType(
+    "FaultyGrid", description="A faulty grid for testing.")
+FaultyGrid["FaultyGrid"] = GridType("FaultyGrid")
+FaultyGrid["FaultyGrid"]["FaultyGrid"] = BaseType(
+    "FaultyGrid", np.arange(6).reshape(2, 3), dimensions=("y", "x"))
+FaultyGrid["x"] = FaultyGrid["FaultyGrid"]["x"] = BaseType(
+    "x", np.arange(3), axis="X", code=1)
+FaultyGrid["y"] = FaultyGrid["FaultyGrid"]["y"] = BaseType(
+    "y", np.arange(2), axis="Y", code=np.int32([]))
diff --git a/src/pydap/tests/test_responses_das.py b/src/pydap/tests/test_responses_das.py
index 95440fc..ff94533 100644
--- a/src/pydap/tests/test_responses_das.py
+++ b/src/pydap/tests/test_responses_das.py
@@ -4,7 +4,9 @@ from webtest import TestApp as App
 from webob.headers import ResponseHeaders
 from pydap.lib import __version__
 from pydap.handlers.lib import BaseHandler
-from pydap.tests.datasets import SimpleSequence, SimpleGrid, SimpleStructure
+from pydap.tests.datasets import (
+    SimpleSequence, SimpleGrid, FaultyGrid, SimpleStructure
+)
 from pydap.responses.das import das
 
 import unittest
@@ -107,6 +109,29 @@ class TestDASResponseGrid(unittest.TestCase):
 """)
 
 
+class TestDASResponseFaultyGrid(unittest.TestCase):
+
+    """Test the DAS response from a grid with empty properties."""
+
+    def test_body(self):
+        """Test the generated DAS response."""
+        app = App(BaseHandler(FaultyGrid))
+        res = app.get('/.das')
+        self.assertEqual(res.text, """Attributes {
+    String description "A faulty grid for testing.";
+    FaultyGrid {
+    }
+    x {
+        String axis "X";
+        Int32 code 1;
+    }
+    y {
+        String axis "Y";
+    }
+}
+""")
+
+
 class TestDASResponseStructure(unittest.TestCase):
 
     """The the DAS response from a structure."""