Index: /issm/trunk-jpl/src/m/qmu/helpers.py
===================================================================
--- /issm/trunk-jpl/src/m/qmu/helpers.py	(revision 27611)
+++ /issm/trunk-jpl/src/m/qmu/helpers.py	(revision 27612)
@@ -6,5 +6,5 @@
 
 class struct(object):
-    """STRUCT class definition - An empty struct that can be assigned arbitrary 
+    """struct class definition - An empty struct that can be assigned arbitrary 
     attributes
     """
@@ -36,6 +36,6 @@
 
 class Lstruct(list):
-    """An empty struct that can be assigned arbitrary attributes but can also be
-    accesed as a list. Eg. x.y = 'hello', x[:] = ['w', 'o', 'r', 'l', 'd']
+    """An empty struct that can be assigned arbitrary attributes but can also 
+    be accessed as a list. Eg. x.y = 'hello', x[:] = ['w', 'o', 'r', 'l', 'd']
 
     Note that 'x' returns the array and x.__dict__ will only return attributes
@@ -48,5 +48,4 @@
 
     Examples:
-
         x = Lstruct(1, 2, 3, 4) -> [1, 2, 3, 4]
         x.a = 'hello'
@@ -88,6 +87,5 @@
 
 class OrderedStruct(object):
-    """
-    A form of dictionary-like structure that maintains the ordering in which
+    """A form of dictionary-like structure that maintains the ordering in which 
     its fields/attributes and their corresponding values were added.
 
@@ -97,11 +95,11 @@
 
     Example:
-        OrderedDict:  # a bit clumsy to use and look at
+        OrderedDict: # A bit clumsy to use and look at
             x['y'] = 5
 
-        OrderedStruct:  # nicer to look at, and works the same way
+        OrderedStruct: # Nicer to look at, and works the same way
             x.y = 5
             OR
-            x['y'] = 5  # supports OrderedDict-style usage
+            x['y'] = 5 # Supports OrderedDict-style usage
 
     Supports: len(x), str(x), for-loop iteration.
@@ -115,23 +113,23 @@
         x = OrderedStruct('y', 5, 'z', 6)
 
-    note below that the output fields as iterables are always in the same
+    Note below that the output fields as iterables are always in the same
     order as the inputs
 
-    x.keys() -> ['y', 'z']
-    x.values() -> [5, 6]
-    x.items() -> [('y', 6), ('z', 6)]
-    x.__dict__ -> [('y', 6), ('z', 6)]
-    vars(x) -> [('y', 6), ('z', 6)]
-
-    x.y -> 5
-    x['y'] -> 5
-    x.z -> 6
-    x['z'] -> 6
-
-    for i in x:  # same as x.items()
-        print i
-     ->
-    ('x', 5)
-    ('y', 6)
+        x.keys() -> ['y', 'z']
+        x.values() -> [5, 6]
+        x.items() -> [('y', 6), ('z', 6)]
+        x.__dict__ -> [('y', 6), ('z', 6)]
+        vars(x) -> [('y', 6), ('z', 6)]
+
+        x.y -> 5
+        x['y'] -> 5
+        x.z -> 6
+        x['z'] -> 6
+
+        for i in x:  # same as x.items()
+            print i
+        ->
+        ('x', 5)
+        ('y', 6)
 
     Note: to access internal fields use dir(x) (input fields will be included,
@@ -178,9 +176,9 @@
             return _v[pos]
         except ValueError:
-            # not in keys, not a valid attribute, raise error
+            # Not in keys, not a valid attribute, raise error
             raise AttributeError('Attribute "' + str(attr) + '" does not exist.')
 
     def __getattribute__(self, attr):
-        # re-route calls to vars(x) and x.__dict__
+        # Re-route calls to vars(x) and x.__dict__
         if attr == '__dict__':
             return OrderedDict(list(self.items()))
@@ -211,8 +209,7 @@
 
     def __copy__(self):
-        """
-        shallow copy, hard copies of trivial attributes,
-        references to structures like lists/OrderedDicts
-        unless redefined as an entirely different structure
+        """shallow copy, hard copies of trivial attributes, references to 
+        structures like lists/OrderedDicts unless redefined as an entirely 
+        different structure
         """
         newInstance = type(self)()
@@ -222,6 +219,5 @@
 
     def __deepcopy__(self, memo=None):
-        """
-        hard copy of all attributes
+        """hard copy of all attributes
         same thing but call deepcopy recursively
         technically not how it should be done,
@@ -256,15 +252,19 @@
 
 def isempty(x):
-    """
-    returns true if object is +/-infinity, NaN, None, '', has length 0, or is
-    an array/matrix composed only of such components (includes mixtures of
+    """Returns true if object is +/-infinity, NaN, None, '', has length 0, or 
+    is an array/matrix composed only of such components (includes mixtures of
     "empty" types)
     """
 
-    if type(x) in [list, np.ndarray, tuple]:
+    if type(x) is list:
+        if len(x) == 0:
+            return True
+
+    if type(x) in [np.ndarray, tuple]:
         if np.size(x) == 0:
             return True
 
-    # if anything in that array/matrix is not empty, the whole thing is not empty
+    if type(x) in [list, np.ndarray, tuple]:
+        # If anything in the array/matrix is not empty, the whole thing is not empty
         try:
             x = np.concatenate(x)
@@ -274,5 +274,5 @@
             if not isempty(i):
                 return False
-    # the array isn't empty but is full of "empty" type objects, so return True
+        # The array isn't empty but is full of "empty" type objects, so return True
         return True
 
@@ -282,5 +282,5 @@
         return True
 
-    # type may not be understood by numpy, in which case it definitely is NOT NaN or infinity
+    # Type may not be understood by NumPy, in which case it definitely is NOT NaN or infinity
     try:
         if np.isnan(x) or np.isinf(x):
@@ -289,11 +289,11 @@
         pass
 
-    # if all of that fails, then it is not empty
+    # If all of the above fails, then it is not empty
     return False
 
 
 def fieldnames(x, ignore_internals=True):
-    """
-    returns a list of fields of x
+    """Returns a list of fields of x
+
     ignore_internals ignores all fieldnames starting with '_' and is True by
     default
@@ -308,6 +308,6 @@
 
 def isfield(x, y, ignore_internals=True):
-    """
-    is y is a field of x?
+    """Returns True if y is a field of x
+
     ignore_internals ignores all fieldnames starting with '_' and is True by
     default
@@ -317,17 +317,15 @@
 
 def fileparts(x):
-    """
-    given:   "path/path/.../file_name.ext"
-    returns: [path, file_name, ext] (list of strings)
+    """given:   "path/path/.../file_name.ext", returns: [path, file_name, ext] (list of strings)
     """
     try:
-        a = x[:x.rindex('/')]  #path
-        b = x[x.rindex('/') + 1:]  #full filename
-    except ValueError:  #no path provided
+        a = x[:x.rindex('/')] # Path
+        b = x[x.rindex('/') + 1:] # Full filename
+    except ValueError: # No path provided
         a = ''
         b = x
     try:
-        c, d = b.split('.')  #file name, extension
-    except ValueError:  #no extension provided
+        c, d = b.split('.') # File name, extension
+    except ValueError: # No extension provided
         return [a, b, '']
     return [a, c, '.' + d]
@@ -349,5 +347,5 @@
     result = str(args[0])
     for i in range(len(args[1:])):
-        # if last argument wasn't empty, add a '/' between it and the next argument
+        # If last argument wasn't empty, add a '/' between it and the next argument
         if len(args[i]) != 0:
             result += '/' + str(args[i + 1])
@@ -358,10 +356,8 @@
 
 def findline(fidi, s):
-    """
-    returns full first line containing s (as a string), or None
-
-    Note: will include any newlines or tabs that occur in that line,
-    use str(findline(f, s)).strip() to remove these, str() in case result is
-    None
+    """returns full first line containing s (as a string), or None
+
+    Note: will include any newlines or tabs that occur in that line, use 
+    str(findline(f, s)).strip() to remove these, str() in case result is None
     """
     for line in fidi:
@@ -372,7 +368,6 @@
 
 def empty_nd_list(shape, filler=0., as_numpy_ndarray=False):
-    """
-    returns a python list of the size/shape given (shape must be int or tuple)
-    the list will be filled with the optional second argument
+    """Returns a python list of the size/shape given (shape must be int or 
+    tuple) the list will be filled with the optional second argument
 
     filler is 0.0 by default
