Repository: pydap/pydap

Issue:
variable name error in pydap 3.2.2
I'm having trouble accessing a dataset with pydap 3.2.2 that worked fine in 3.2.1. I think 3.2.2 mangles the variable name. I briefly looked at the source, but it wasn't clear to me where the problem was.

pydap 3.2.1

```
>>> from pydap.client import open_url
>>> dataset = open_url('https://nomads.ncdc.noaa.gov/thredds/dodsC/gfs-004/201612/20161201/gfs_4_20161201_0000_003.grb2')
>>> tsurf = dataset['Temperature_surface']
>>> tsurf[0, 0, 0]
<GridType with array 'Temperature_surface' and maps 'time', 'lat', 'lon'>
```

pydap 3.2.2

```
>>> from pydap.client import open_url
>>> dataset = open_url('https://nomads.ncdc.noaa.gov/thredds/dodsC/gfs-004/201612/20161201/gfs_4_20161201_0000_003.grb2')
>>> tsurf = dataset['Temperature_surface']
>>> tsurf[0, 0, 0]
Traceback (most recent call last):
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/model.py", line 404, in _getitem_string
    return self._dict[quote(key)]
KeyError: 'Temperature_surface%2ETemperature_surface'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/model.py", line 740, in __getitem__
    var.data = self[var.name].data[slice_]
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/handlers/dap.py", line 149, in __getitem__
    return dataset[self.id].data
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/model.py", line 425, in __getitem__
    return self._getitem_string(key)
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/model.py", line 409, in _getitem_string
    return self[splitted[0]]['.'.join(splitted[1:])]
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/model.py", line 320, in __getitem__
    out.data = self._get_data_index(index)
  File "/Users/holmgren/miniconda3/envs/pydap322/lib/python3.6/site-packages/pydap/model.py", line 349, in _get_data_index
    return self._data[index]
IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices
```

Discussion:
laliberte: I'm going to merge this one right since it mostly does some basic housekeeping that are necessary for successful builds and it solves a critical bug.

Patch:
diff --git a/src/pydap/handlers/csv/__init__.py b/src/pydap/handlers/csv/__init__.py
index 38ded4c..717079b 100644
--- a/src/pydap/handlers/csv/__init__.py
+++ b/src/pydap/handlers/csv/__init__.py
@@ -114,7 +114,7 @@ class CSVHandler(BaseHandler):
         BaseHandler.__init__(self)
 
         try:
-            with open(filepath, 'Ur') as fp:
+            with open(filepath, 'r') as fp:
                 reader = csv.reader(fp, quoting=csv.QUOTE_NONNUMERIC)
                 vars = next(reader)
         except Exception as exc:
@@ -257,7 +257,7 @@ class CSVData(IterData):
     def stream(self):
         """Generator that yield lines of the file."""
         try:
-            with open(self.filepath, 'Ur') as fp:
+            with open(self.filepath, 'r') as fp:
                 reader = csv.reader(fp, quoting=csv.QUOTE_NONNUMERIC)
                 next(reader)  # consume var names
                 for row in reader:
diff --git a/src/pydap/handlers/lib.py b/src/pydap/handlers/lib.py
index dca98b8..ffef4e8 100644
--- a/src/pydap/handlers/lib.py
+++ b/src/pydap/handlers/lib.py
@@ -120,7 +120,7 @@ class BaseHandler(object):
                     'Origin, X-Requested-With, Content-Type')
 
             return res(environ, start_response)
-        except:
+        except Exception:
             # should the exception be catched?
             if environ.get('x-wsgiorg.throw_errors'):
                 raise
@@ -456,7 +456,7 @@ def build_filter(expression, template):
             col = keys.index(token)
             target = target[token]
         a = operator.itemgetter(col)
-    except:
+    except Exception:
         raise ConstraintExpressionError(
             'Invalid constraint expression: "{expression}" '
             '("{id}" is not a valid variable)'.format(
@@ -474,7 +474,7 @@ def build_filter(expression, template):
 
             def b(row):
                 return value
-        except:
+        except Exception:
             raise ConstraintExpressionError(
                 'Invalid constraint expression: "{expression}" '
                 '("{id}" is not valid)'.format(
diff --git a/src/pydap/lib.py b/src/pydap/lib.py
index ed55eb9..7bfc7ea 100644
--- a/src/pydap/lib.py
+++ b/src/pydap/lib.py
@@ -125,7 +125,7 @@ def encode(obj):
     """Return an object encoded to its DAP representation."""
     try:
         return '%.6g' % obj
-    except:
+    except Exception:
         return '"{0}"'.format(obj)
 
 
diff --git a/src/pydap/model.py b/src/pydap/model.py
index 335f0c3..ee9b486 100644
--- a/src/pydap/model.py
+++ b/src/pydap/model.py
@@ -381,7 +381,7 @@ class StructureType(DapType, Mapping):
         """Lazy shortcut return children."""
         try:
             return self[attr]
-        except:
+        except Exception:
             return DapType.__getattr__(self, attr)
 
     def __contains__(self, key):
@@ -408,7 +408,7 @@ class StructureType(DapType, Mapping):
             if len(splitted) > 1:
                 try:
                     return self[splitted[0]]['.'.join(splitted[1:])]
-                except KeyError:
+                except (KeyError, IndexError):
                     return self['.'.join(splitted[1:])]
             else:
                 raise
diff --git a/src/pydap/parsers/__init__.py b/src/pydap/parsers/__init__.py
index 7068faa..aab33ed 100644
--- a/src/pydap/parsers/__init__.py
+++ b/src/pydap/parsers/__init__.py
@@ -74,12 +74,12 @@ def parse_selection(expression, dataset):
 
     try:
         id1 = get_var(dataset, id1)
-    except:
+    except Exception:
         id1 = ast.literal_eval(id1)
 
     try:
         id2 = get_var(dataset, id2)
-    except:
+    except Exception:
         id2 = ast.literal_eval(id2)
 
     return id1, op, id2
diff --git a/src/pydap/wsgi/app.py b/src/pydap/wsgi/app.py
index b735b10..578187e 100644
--- a/src/pydap/wsgi/app.py
+++ b/src/pydap/wsgi/app.py
@@ -155,7 +155,7 @@ def alphanum_key(s):
     def tryint(s):
         try:
             return int(s)
-        except:
+        except Exception:
             return s
     return [tryint(c) for c in re.split('([0-9]+)', s)]
 
diff --git a/src/pydap/wsgi/ssf.py b/src/pydap/wsgi/ssf.py
index e85eed4..785c7d4 100644
--- a/src/pydap/wsgi/ssf.py
+++ b/src/pydap/wsgi/ssf.py
@@ -183,10 +183,10 @@ def eval_function(dataset, function, functions):
             try:
                 names = re.sub(r'\[.*?\]', '', str(token)).split('.')
                 return reduce(operator.getitem, [dataset] + names)
-            except:
+            except Exception:
                 try:
                     return ast.literal_eval(token)
-                except:
+                except Exception:
                     return token
 
     args = map(parse, tokenize(args))


Test patch:
diff --git a/src/pydap/tests/test_model.py b/src/pydap/tests/test_model.py
index c2e8fee..35e7e77 100644
--- a/src/pydap/tests/test_model.py
+++ b/src/pydap/tests/test_model.py
@@ -248,8 +248,10 @@ def test_StructureType_getitem():
     """Test item retrieval."""
     var = StructureType("var")
     child = BaseType("child")
+    child.data = np.array([[[0, 1]]])
     var["child"] = child
     assert var["child"] is child
+    assert var["child.child"] is child
     with pytest.raises(KeyError):
         var["unloved child"]
     with pytest.raises(KeyError):
diff --git a/src/pydap/tests/test_responses_error.py b/src/pydap/tests/test_responses_error.py
index 70e35ab..3c9f06e 100644
--- a/src/pydap/tests/test_responses_error.py
+++ b/src/pydap/tests/test_responses_error.py
@@ -11,7 +11,7 @@ class TestErrorResponse(unittest.TestCase):
         # create an exception that would happen in runtime
         try:
             1/0
-        except:
+        except Exception:
             error = ErrorResponse(sys.exc_info())
 
         req = Request.blank('/')