Repository: pydap/pydap
Pull request #403 (2024-10-30 01:53:16)

Parse attribute elements with atomic types on root
<!-- Thank you very much for your hard work and contribution! -->

The following Pull Request:

- [x] Closes issue #402. 
- [x] Test added to make sure parser gets one (and therefore all) attributes from test dmr



Patch:
diff --git a/src/pydap/parsers/dmr.py b/src/pydap/parsers/dmr.py
index 6ff63d5..08782dc 100644
--- a/src/pydap/parsers/dmr.py
+++ b/src/pydap/parsers/dmr.py
@@ -80,44 +80,43 @@ def get_dtype(element):
     return dtype
 
 
-def get_attributes(element, attributes={}):
-    attribute_elements = element.findall("Attribute")
+def get_atomic_attr(element):
     Float_types = ["Float32", "float", "Float64"]
     Int_types = ["Int16", "Int32", "Int64", "int", "Int8"]
     uInt_types = ["uInt16", "uInt32", "uInt64", "uint", "uInt8", "Char"]
-    for attribute_element in attribute_elements:
-        name = attribute_element.get("name")
-        value = attribute_element.find("Value").text
-        if value is None:
-            # This could be because server is TDS.
-            # If value is None still, then data is missing
-            value = attribute_element.find("Value").get("value")
-        _type = attribute_element.get("type")
-        if _type in dmr_atomic_types and value is not None:
-            if _type in Float_types:
-                # keep float-type of value
-                value = float(value)
-            elif _type in Int_types or _type in uInt_types:
-                # keeps integer-type of value
-                value = int(value)
-            else:
-                try:
-                    value = ast.literal_eval(value)
-                except ValueError:
-                    # leaves value as string
-                    raise Warning(
-                        """
-                        Pydap could not turn the non-string Attribute: `{}`
-                        with value `{}` into a numeric type during parsing
-                        of the `DMR`. Parsing as string value instead. If you
-                        think this is a bug consider raising a issue. To
-                        learn more about DAP's atomic types, go to:
-                        https://docs.opendap.org/index.php/
-                        DAP4:_Specification_Volume_1#Atomic_Types
-                        """.format(
-                            name, value
-                        )
+    name = element.get("name")
+    value = element.find("Value").text
+    if value is None:
+        # This could be because server is TDS.
+        # If value is None still, then data is missing
+        value = element.find("Value").get("value")
+    _type = element.get("type")
+    if _type in dmr_atomic_types and value is not None:
+        if _type in Float_types:
+            # keep float-type of value
+            value = float(value)
+        elif _type in Int_types or _type in uInt_types:
+            # keeps integer-type of value
+            value = int(value)
+        else:
+            try:
+                value = ast.literal_eval(value)
+            except ValueError:
+                # leaves value as string
+                raise Warning(
+                    """
+                    Pydap failed to retrieve Attribute: `{}` element during
+                    parsing of the `DMR`.""".format(
+                        name
                     )
+                )
+    return name, value
+
+
+def get_attributes(element, attributes={}):
+    attribute_elements = element.findall("Attribute")
+    for attribute_element in attribute_elements:
+        name, value = get_atomic_attr(attribute_element)
         attributes[name] = value
     return attributes
 
@@ -297,7 +296,15 @@ class DMRParser(object):
         Attrs = {}
         for subnode in self.node:
             if subnode.get("name") in AttsNames:
-                Attrs = get_attributes(subnode, Attrs)
+                if subnode.get("type") not in dmr_atomic_types + (
+                    "String",
+                    "URI",
+                ):
+                    # container type
+                    Attrs = get_attributes(subnode, Attrs)
+                else:
+                    name, value = get_atomic_attr(subnode)
+                    Attrs[name] = value
         dataset.attributes = Attrs
         # create Groups via dict
         Groups = get_groups(self.node)


Test patch:
diff --git a/src/pydap/tests/test_parsers_dmr.py b/src/pydap/tests/test_parsers_dmr.py
index e7004e4..743dabf 100644
--- a/src/pydap/tests/test_parsers_dmr.py
+++ b/src/pydap/tests/test_parsers_dmr.py
@@ -83,6 +83,7 @@ class TestDMRParser(unittest.TestCase):
         self.assertEqual(
             dataset["sea_ice_fraction"].dimensions, ["/time", "/lat", "/lon"]
         )
+        self.assertEqual(dataset.attributes["Conventions"], "CF-1.7")
 
     def test_mod05(self):
         dataset = load_dmr_file(