Continued improving the variable dumping of the debugger backends.

Mon, 19 Sep 2016 20:10:33 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 19 Sep 2016 20:10:33 +0200
changeset 5175
9db0b0f15d12
parent 5173
632257ad7337
child 5176
30547e9a19e3

Continued improving the variable dumping of the debugger backends.

DebugClients/Python2/DebugClientBase.py file | annotate | diff | comparison | revisions
DebugClients/Python2/DebugVariables.py file | annotate | diff | comparison | revisions
DebugClients/Python3/DebugClientBase.py file | annotate | diff | comparison | revisions
DebugClients/Python3/DebugVariables.py file | annotate | diff | comparison | revisions
Debugger/VariablesViewer.py file | annotate | diff | comparison | revisions
--- a/DebugClients/Python2/DebugClientBase.py	Fri Sep 16 19:34:58 2016 +0200
+++ b/DebugClients/Python2/DebugClientBase.py	Mon Sep 19 20:10:33 2016 +0200
@@ -1442,18 +1442,21 @@
                     DebugVariables.getType(variable)
                 if resolver:
                     variable = resolver.resolve(variable, attribute)
+                    if variable is None:
+                        break
                 else:
                     break
-            typeObject, typeName, typeStr, resolver = \
-                DebugVariables.getType(variable)
-            if typeStr.startswith(("PyQt5.", "PyQt4.")):
-                vlist = self.__formatQtVariable(variable, typeName)
-                varlist.extend(vlist)
-            elif resolver:
-                dict = resolver.getDictionary(variable)
-                vlist = self.__formatVariablesList(
-                    list(dict.keys()), dict, scope, filter)
-                varlist.extend(vlist)
+            if variable is not None:
+                typeObject, typeName, typeStr, resolver = \
+                    DebugVariables.getType(variable)
+                if typeStr.startswith(("PyQt5.", "PyQt4.")):
+                    vlist = self.__formatQtVariable(variable, typeName)
+                    varlist.extend(vlist)
+                elif resolver:
+                    dict = resolver.getDictionary(variable)
+                    vlist = self.__formatVariablesList(
+                        list(dict.keys()), dict, scope, filter)
+                    varlist.extend(vlist)
         
         self.sendJsonCommand("ResponseVariable", {
             "scope": scope,
@@ -1664,21 +1667,21 @@
             else:
                 value = dict[key]
                 valtypestr = ("%s" % type(value))[1:-1]
+                valtypename = type(value).__name__
                 
-                if valtypestr.split(' ', 1)[0] == 'class':
+                if valtypestr.startswith('class '):
                     # handle new class type of python 2.2+
                     if ConfigVarTypeStrings.index('instance') in filter:
                         continue
                     valtype = valtypestr
                 else:
                     valtype = valtypestr[6:-1]
-                    try:
-                        if ConfigVarTypeStrings.index(valtype) in filter:
-                            continue
-                    except ValueError:
-                        if valtype == "classobj":
-                            if ConfigVarTypeStrings.index(
-                                    'instance') in filter:
+                    if valtype not in ConfigVarTypeStrings:
+                        if valtype == "numpy.ndarray":
+                            if ConfigVarTypeStrings.index('list') in filter:
+                                continue
+                        elif valtypename == "MultiValueDict":
+                            if ConfigVarTypeStrings.index('dict') in filter:
                                 continue
                         elif valtype == "sip.methoddescriptor":
                             if ConfigVarTypeStrings.index(
@@ -1687,22 +1690,51 @@
                         elif valtype == "sip.enumtype":
                             if ConfigVarTypeStrings.index('class') in filter:
                                 continue
-                        elif not valtype.startswith("PySide") and \
-                                ConfigVarTypeStrings.index('other') in filter:
+                        elif ConfigVarTypeStrings.index('instance') in filter:
                             continue
+                        
+                        if valtypename not in ["MultiValueDict"] and \
+                                not valtype.startswith("numpy"):
+                            valtype = valtypestr
+                    else:
+                        try:
+                            if ConfigVarTypeStrings.index(valtype) in filter:
+                                continue
+                        except ValueError:
+                            if valtype == "classobj":
+                                if ConfigVarTypeStrings.index(
+                                        'instance') in filter:
+                                    continue
+                            elif valtype == "sip.methoddescriptor":
+                                if ConfigVarTypeStrings.index(
+                                        'method') in filter:
+                                    continue
+                            elif valtype == "sip.enumtype":
+                                if ConfigVarTypeStrings.index('class') in \
+                                        filter:
+                                    continue
+                            elif not valtype.startswith("PySide") and \
+                                ConfigVarTypeStrings.index('other') in \
+                                    filter:
+                                continue
                     
                 try:
-                    if valtype not in ['list', 'tuple', 'dict', 'set',
-                                       'frozenset']:
+                    if valtype in ['list', 'tuple', 'dict', 'set',
+                                   'frozenset']:
+                        if valtype == 'dict':
+                            rvalue = "%d" % len(value.keys())
+                        else:
+                            rvalue = "%d" % len(value)
+                    elif valtype == "numpy.ndarray":
+                        rvalue = "%d" % value.size
+                    elif valtypename == "MultiValueDict":
+                        rvalue = "%d" % len(value.keys())
+                        valtype = "django.MultiValueDict"  # shortened type
+                    else:
                         rvalue = repr(value)
                         if valtype.startswith('class') and \
                            rvalue[0] in ['{', '(', '[']:
                             rvalue = ""
-                    else:
-                        if valtype == 'dict':
-                            rvalue = "%d" % len(value.keys())
-                        else:
-                            rvalue = "%d" % len(value)
                 except Exception:
                     rvalue = ''
                 
--- a/DebugClients/Python2/DebugVariables.py	Fri Sep 16 19:34:58 2016 +0200
+++ b/DebugClients/Python2/DebugVariables.py	Mon Sep 19 20:10:33 2016 +0200
@@ -54,6 +54,11 @@
         raise NotImplementedError
 
 
+############################################################
+## Default Resolver
+############################################################
+
+
 class DefaultResolver(BaseResolver):
     """
     Class used to resolve the default way.
@@ -69,7 +74,7 @@
         @return value of the attribute
         @rtype any
         """
-        return getattr(var, attribute)
+        return getattr(var, attribute, None)
     
     def getDictionary(self, var):
         """
@@ -95,6 +100,11 @@
         return d
 
 
+############################################################
+## Resolver for Dictionaries
+############################################################
+
+
 class DictResolver(BaseResolver):
     """
     Class used to resolve from a dictionary.
@@ -117,7 +127,7 @@
             try:
                 return var[attribute]
             except Exception:
-                return getattr(var, attribute)
+                return getattr(var, attribute, None)
         
         expectedID = int(attribute.split("(ID:")[-1][:-1])
         for key, value in var.items():
@@ -126,9 +136,9 @@
         
         return None
     
-    def __keyToStr(self, key):
+    def keyToStr(self, key):
         """
-        Private method to get a string representation for a key.
+        Public method to get a string representation for a key.
         
         @param key key to be converted
         @type any
@@ -153,7 +163,7 @@
         count = 0
         for key, value in var.items():
             count += 1
-            key = "%s (ID:%s)" % (self.__keyToStr(key), id(key))
+            key = "%s (ID:%s)" % (self.keyToStr(key), id(key))
             d[key] = value
             if count > MaxItemsToHandle:
                 d[TooLargeAttribute] = TooLargeMessage
@@ -168,6 +178,11 @@
         return d
 
 
+############################################################
+## Resolver for Lists and Tuples
+############################################################
+
+
 class ListResolver(BaseResolver):
     """
     Class used to resolve from a tuple or list.
@@ -189,7 +204,7 @@
         try:
             return var[int(attribute)]
         except Exception:
-            return getattr(var, attribute)
+            return getattr(var, attribute, None)
     
     def getDictionary(self, var):
         """
@@ -218,6 +233,11 @@
         return d
 
 
+############################################################
+## Resolver for Sets and Frozensets
+############################################################
+
+
 class SetResolver(BaseResolver):
     """
     Class used to resolve from a set or frozenset.
@@ -236,12 +256,12 @@
         if attribute in ('___len___', TooLargeAttribute):
             return None
         
-        if attribute.startswith("ID:"):
+        if attribute.startswith("ID: "):
             attribute = attribute.split(None, 1)[1]
         try:
             attribute = int(attribute)
         except Exception:
-            return getattr(var, attribute)
+            return getattr(var, attribute, None)
 
         for v in var:
             if id(v) == attribute:
@@ -276,14 +296,190 @@
         return d
 
 
+############################################################
+## Resolver for Numpy Arrays
+############################################################
+
+
+class NdArrayResolver(BaseResolver):
+    """
+    Class used to resolve from numpy ndarray including some meta data.
+    """
+    def __isNumeric(self, arr):
+        """
+        Private method to check, if an array is of a numeric type.
+        
+        @param arr array to check
+        @type ndarray
+        @return flag indicating a numeric array
+        @rtype bool
+        """
+        try:
+            return arr.dtype.kind in 'biufc'
+        except AttributeError:
+            return False
+    
+    def resolve(self, var, attribute):
+        """
+        Public method to get an attribute from a variable.
+        
+        @param var variable to extract an attribute or value from
+        @type tuple or list
+        @param attribute id of the value to extract
+        @type str
+        @return value of the attribute
+        @rtype any
+        """
+        if attribute == '__internals__':
+            return defaultResolver.getDictionary(var)
+        
+        if attribute == 'min':
+            if self.__isNumeric(var):
+                return var.min()
+            else:
+                return None
+        
+        if attribute == 'max':
+            if self.__isNumeric(var):
+                return var.max()
+            else:
+                return None
+        
+        if attribute == 'mean':
+            if self.__isNumeric(var):
+                return var.mean()
+            else:
+                return None
+        
+        if attribute == 'shape':
+            return var.shape
+        
+        if attribute == 'dtype':
+            return var.dtype
+        
+        if attribute == 'size':
+            return var.size
+        
+        if attribute.startswith('['):
+            container = NdArrayItemsContainer()
+            count = 0
+            for element in var:
+                setattr(container, str(count), element)
+                count += 1
+                if count > MaxItemsToHandle:
+                    setattr(container, TooLargeAttribute, TooLargeMessage)
+                    break
+            return container
+        
+        return None
+    
+    def getDictionary(self, var):
+        """
+        Public method to get the attributes of a variable as a dictionary.
+        
+        @param var variable to be converted
+        @type any
+        @return dictionary containing the variable attributes
+        @rtype dict
+        """
+        d = {}
+        d['__internals__'] = defaultResolver.getDictionary(var)
+        if var.size > 1024 * 1024:
+            d['min'] = 'ndarray too big, calculating min would slow down' \
+                       ' debugging'
+            d['max'] = 'ndarray too big, calculating max would slow down' \
+                       ' debugging'
+        else:
+            if self.__isNumeric(var):
+                d['min'] = var.min()
+                d['max'] = var.max()
+                d['mean'] = var.mean()
+            else:
+                d['min'] = 'not a numeric object'
+                d['max'] = 'not a numeric object'
+                d['mean'] = 'not a numeric object'
+        d['shape'] = var.shape
+        d['dtype'] = var.dtype
+        d['size'] = var.size
+        d['[0:{0}]'.format(len(var) - 1)] = list(var[0:MaxItemsToHandle])
+        return d
+
+
+class NdArrayItemsContainer:
+    """
+    Class to store ndarray items.
+    """
+    pass
+
+
+############################################################
+## Resolver for Django Multi Value Dictionaries
+############################################################
+
+
+class MultiValueDictResolver(DictResolver):
+    """
+    Class used to resolve from Django multi value dictionaries.
+    """
+    def resolve(self, var, attribute):
+        """
+        Public method to get an attribute from a variable.
+        
+        @param var variable to extract an attribute or value from
+        @type dict
+        @param attribute name of the attribute to extract
+        @type str
+        @return value of the attribute
+        @rtype any
+        """
+        if attribute in ('___len___', TooLargeAttribute):
+            return None
+        
+        if "(ID:" not in attribute:
+            try:
+                return var[attribute]
+            except Exception:
+                return getattr(var, attribute, None)
+        
+        expectedID = int(attribute.split("(ID:")[-1][:-1])
+        for key in var.keys():
+            if id(key) == expectedID:
+                value = var.getlist(key)
+                return value
+        
+        return None
+    
+    def getDictionary(self, var):
+        """
+        Public method to get the attributes of a variable as a dictionary.
+        
+        @param var variable to be converted
+        @type any
+        @return dictionary containing the variable attributes
+        @rtype dict
+        """
+        d = {}
+        count = 0
+        for key in var.keys():
+            count += 1
+            value = var.getlist(key)
+            key = "{0} (ID:{1})".format(self.keyToStr(key), id(key))
+            d[key] = value
+            if count > MaxItemsToHandle:
+                d[TooLargeAttribute] = TooLargeMessage
+                break
+        
+        d["___len___"] = len(var)
+        
+        return d
+
+
 defaultResolver = DefaultResolver()
 dictResolver = DictResolver()
 listResolver = ListResolver()
 setResolver = SetResolver()
-
-# TODO: add resolver for numpy arrays
-# TODO: add resolver for Django MultiValueDict
-# TODO: add resolver for collections.deque
+ndarrayResolver = NdArrayResolver()
+multiValueDictResolver = MultiValueDictResolver()
 
 ############################################################
 ## Methods to determine the type of a variable and the
@@ -329,6 +525,19 @@
         _TypeMap.append((frozenset, setResolver))     # __IGNORE_WARNING__
     except Exception:
         pass    # not available on all python versions
+    
+    try:
+        import numpy
+        _TypeMap.append((numpy.ndarray, ndarrayResolver))
+    except ImportError:
+        pass  # numpy may not be installed
+    
+    try:
+        from django.utils.datastructures import MultiValueDict
+        _TypeMap.insert(0, (MultiValueDict, multiValueDictResolver))
+        # it should go before dict
+    except ImportError:
+        pass  # django may not be installed
 
 
 def getType(obj):
--- a/DebugClients/Python3/DebugClientBase.py	Fri Sep 16 19:34:58 2016 +0200
+++ b/DebugClients/Python3/DebugClientBase.py	Mon Sep 19 20:10:33 2016 +0200
@@ -1441,18 +1441,21 @@
                     DebugVariables.getType(variable)
                 if resolver:
                     variable = resolver.resolve(variable, attribute)
+                    if variable is None:
+                        break
                 else:
                     break
-            typeObject, typeName, typeStr, resolver = \
-                DebugVariables.getType(variable)
-            if typeStr.startswith(("PyQt5.", "PyQt4.")):
-                vlist = self.__formatQtVariable(variable, typeName)
-                varlist.extend(vlist)
-            elif resolver:
-                dict = resolver.getDictionary(variable)
-                vlist = self.__formatVariablesList(
-                    list(dict.keys()), dict, scope, filter)
-                varlist.extend(vlist)
+            if variable is not None:
+                typeObject, typeName, typeStr, resolver = \
+                    DebugVariables.getType(variable)
+                if typeStr.startswith(("PyQt5.", "PyQt4.")):
+                    vlist = self.__formatQtVariable(variable, typeName)
+                    varlist.extend(vlist)
+                elif resolver:
+                    dict = resolver.getDictionary(variable)
+                    vlist = self.__formatVariablesList(
+                        list(dict.keys()), dict, scope, filter)
+                    varlist.extend(vlist)
         
         self.sendJsonCommand("ResponseVariable", {
             "scope": scope,
@@ -1670,11 +1673,15 @@
             else:
                 value = dict[key]
                 valtypestr = str(type(value))[1:-1]
-                
                 valtype = valtypestr[7:-1]
+                valtypename = type(value).__name__
                 if valtype not in ConfigVarTypeStrings:
-                    if ConfigVarTypeStrings.index('instance') in filter:
-                        continue
+                    if valtype == "numpy.ndarray":
+                        if ConfigVarTypeStrings.index('list') in filter:
+                            continue
+                    elif valtypename == "MultiValueDict":
+                        if ConfigVarTypeStrings.index('dict') in filter:
+                            continue
                     elif valtype == "sip.methoddescriptor":
                         if ConfigVarTypeStrings.index(
                                 'method') in filter:
@@ -1682,7 +1689,11 @@
                     elif valtype == "sip.enumtype":
                         if ConfigVarTypeStrings.index('class') in filter:
                             continue
-                    valtype = valtypestr
+                    elif ConfigVarTypeStrings.index('instance') in filter:
+                        continue
+                    
+                    if valtypename not in ["ndarray", "MultiValueDict"]:
+                        valtype = valtypestr
                 else:
                     try:
                         if ConfigVarTypeStrings.index(valtype) in filter:
@@ -1704,17 +1715,22 @@
                             continue
                 
                 try:
-                    if valtype not in ['list', 'tuple', 'dict', 'set',
-                                       'frozenset']:
+                    if valtype in ['list', 'tuple', 'dict', 'set',
+                                   'frozenset']:
+                        if valtype == 'dict':
+                            rvalue = "{0:d}".format(len(value.keys()))
+                        else:
+                            rvalue = "{0:d}".format(len(value))
+                    elif valtype == "numpy.ndarray":
+                        rvalue = "{0:d}".format(value.size)
+                    elif valtypename == "MultiValueDict":
+                        rvalue = "{0:d}".format(len(value.keys()))
+                        valtype = "django.MultiValueDict"  # shortened type
+                    else:
                         rvalue = repr(value)
                         if valtype.startswith('class') and \
                            rvalue[0] in ['{', '(', '[']:
                             rvalue = ""
-                    else:
-                        if valtype == 'dict':
-                            rvalue = "{0:d}".format(len(value.keys()))
-                        else:
-                            rvalue = "{0:d}".format(len(value))
                 except Exception:
                     rvalue = ''
             
--- a/DebugClients/Python3/DebugVariables.py	Fri Sep 16 19:34:58 2016 +0200
+++ b/DebugClients/Python3/DebugVariables.py	Mon Sep 19 20:10:33 2016 +0200
@@ -54,6 +54,11 @@
         raise NotImplementedError
 
 
+############################################################
+## Default Resolver
+############################################################
+
+
 class DefaultResolver(BaseResolver):
     """
     Class used to resolve the default way.
@@ -69,7 +74,7 @@
         @return value of the attribute
         @rtype any
         """
-        return getattr(var, attribute)
+        return getattr(var, attribute, None)
     
     def getDictionary(self, var):
         """
@@ -95,6 +100,11 @@
         return d
 
 
+############################################################
+## Resolver for Dictionaries
+############################################################
+
+
 class DictResolver(BaseResolver):
     """
     Class used to resolve from a dictionary.
@@ -117,7 +127,7 @@
             try:
                 return var[attribute]
             except Exception:
-                return getattr(var, attribute)
+                return getattr(var, attribute, None)
         
         expectedID = int(attribute.split("(ID:")[-1][:-1])
         for key, value in var.items():
@@ -126,9 +136,9 @@
         
         return None
     
-    def __keyToStr(self, key):
+    def keyToStr(self, key):
         """
-        Private method to get a string representation for a key.
+        Public method to get a string representation for a key.
         
         @param key key to be converted
         @type any
@@ -153,7 +163,7 @@
         count = 0
         for key, value in var.items():
             count += 1
-            key = "{0} (ID:{1})".format(self.__keyToStr(key), id(key))
+            key = "{0} (ID:{1})".format(self.keyToStr(key), id(key))
             d[key] = value
             if count > MaxItemsToHandle:
                 d[TooLargeAttribute] = TooLargeMessage
@@ -168,6 +178,11 @@
         return d
 
 
+############################################################
+## Resolver for Lists and Tuples
+############################################################
+
+
 class ListResolver(BaseResolver):
     """
     Class used to resolve from a tuple or list.
@@ -189,7 +204,7 @@
         try:
             return var[int(attribute)]
         except Exception:
-            return getattr(var, attribute)
+            return getattr(var, attribute, None)
     
     def getDictionary(self, var):
         """
@@ -218,6 +233,11 @@
         return d
 
 
+############################################################
+## Resolver for Sets and Frozensets
+############################################################
+
+
 class SetResolver(BaseResolver):
     """
     Class used to resolve from a set or frozenset.
@@ -236,12 +256,12 @@
         if attribute in ('___len___', TooLargeAttribute):
             return None
 
-        if attribute.startswith("ID:"):
+        if attribute.startswith("ID: "):
             attribute = attribute.split(None, 1)[1]
         try:
             attribute = int(attribute)
         except Exception:
-            return getattr(var, attribute)
+            return getattr(var, attribute, None)
 
         for v in var:
             if id(v) == attribute:
@@ -276,14 +296,190 @@
         return d
 
 
+############################################################
+## Resolver for Numpy Arrays
+############################################################
+
+
+class NdArrayResolver(BaseResolver):
+    """
+    Class used to resolve from numpy ndarray including some meta data.
+    """
+    def __isNumeric(self, arr):
+        """
+        Private method to check, if an array is of a numeric type.
+        
+        @param arr array to check
+        @type ndarray
+        @return flag indicating a numeric array
+        @rtype bool
+        """
+        try:
+            return arr.dtype.kind in 'biufc'
+        except AttributeError:
+            return False
+    
+    def resolve(self, var, attribute):
+        """
+        Public method to get an attribute from a variable.
+        
+        @param var variable to extract an attribute or value from
+        @type tuple or list
+        @param attribute id of the value to extract
+        @type str
+        @return value of the attribute
+        @rtype any
+        """
+        if attribute == '__internals__':
+            return defaultResolver.getDictionary(var)
+        
+        if attribute == 'min':
+            if self.__isNumeric(var):
+                return var.min()
+            else:
+                return None
+        
+        if attribute == 'max':
+            if self.__isNumeric(var):
+                return var.max()
+            else:
+                return None
+        
+        if attribute == 'mean':
+            if self.__isNumeric(var):
+                return var.mean()
+            else:
+                return None
+        
+        if attribute == 'shape':
+            return var.shape
+        
+        if attribute == 'dtype':
+            return var.dtype
+        
+        if attribute == 'size':
+            return var.size
+        
+        if attribute.startswith('['):
+            container = NdArrayItemsContainer()
+            count = 0
+            for element in var:
+                setattr(container, str(count), element)
+                count += 1
+                if count > MaxItemsToHandle:
+                    setattr(container, TooLargeAttribute, TooLargeMessage)
+                    break
+            return container
+        
+        return None
+    
+    def getDictionary(self, var):
+        """
+        Public method to get the attributes of a variable as a dictionary.
+        
+        @param var variable to be converted
+        @type any
+        @return dictionary containing the variable attributes
+        @rtype dict
+        """
+        d = {}
+        d['__internals__'] = defaultResolver.getDictionary(var)
+        if var.size > 1024 * 1024:
+            d['min'] = 'ndarray too big, calculating min would slow down' \
+                       ' debugging'
+            d['max'] = 'ndarray too big, calculating max would slow down' \
+                       ' debugging'
+        else:
+            if self.__isNumeric(var):
+                d['min'] = var.min()
+                d['max'] = var.max()
+                d['mean'] = var.mean()
+            else:
+                d['min'] = 'not a numeric object'
+                d['max'] = 'not a numeric object'
+                d['mean'] = 'not a numeric object'
+        d['shape'] = var.shape
+        d['dtype'] = var.dtype
+        d['size'] = var.size
+        d['[0:{0}]'.format(len(var) - 1)] = list(var[0:MaxItemsToHandle])
+        return d
+
+
+class NdArrayItemsContainer:
+    """
+    Class to store ndarray items.
+    """
+    pass
+
+
+############################################################
+## Resolver for Django Multi Value Dictionaries
+############################################################
+
+
+class MultiValueDictResolver(DictResolver):
+    """
+    Class used to resolve from Django multi value dictionaries.
+    """
+    def resolve(self, var, attribute):
+        """
+        Public method to get an attribute from a variable.
+        
+        @param var variable to extract an attribute or value from
+        @type dict
+        @param attribute name of the attribute to extract
+        @type str
+        @return value of the attribute
+        @rtype any
+        """
+        if attribute in ('___len___', TooLargeAttribute):
+            return None
+        
+        if "(ID:" not in attribute:
+            try:
+                return var[attribute]
+            except Exception:
+                return getattr(var, attribute, None)
+        
+        expectedID = int(attribute.split("(ID:")[-1][:-1])
+        for key in var.keys():
+            if id(key) == expectedID:
+                value = var.getlist(key)
+                return value
+        
+        return None
+    
+    def getDictionary(self, var):
+        """
+        Public method to get the attributes of a variable as a dictionary.
+        
+        @param var variable to be converted
+        @type any
+        @return dictionary containing the variable attributes
+        @rtype dict
+        """
+        d = {}
+        count = 0
+        for key in var.keys():
+            count += 1
+            value = var.getlist(key)
+            key = "{0} (ID:{1})".format(self.keyToStr(key), id(key))
+            d[key] = value
+            if count > MaxItemsToHandle:
+                d[TooLargeAttribute] = TooLargeMessage
+                break
+        
+        d["___len___"] = len(var)
+        
+        return d
+
+
 defaultResolver = DefaultResolver()
 dictResolver = DictResolver()
 listResolver = ListResolver()
 setResolver = SetResolver()
-
-# TODO: add resolver for numpy arrays
-# TODO: add resolver for Django MultiValueDict
-# TODO: add resolver for collections.deque
+ndarrayResolver = NdArrayResolver()
+multiValueDictResolver = MultiValueDictResolver()
 
 ############################################################
 ## Methods to determine the type of a variable and the
@@ -329,6 +525,19 @@
         _TypeMap.append((frozenset, setResolver))     # __IGNORE_WARNING__
     except Exception:
         pass    # not available on all python versions
+    
+    try:
+        import numpy
+        _TypeMap.append((numpy.ndarray, ndarrayResolver))
+    except ImportError:
+        pass  # numpy may not be installed
+    
+    try:
+        from django.utils.datastructures import MultiValueDict
+        _TypeMap.insert(0, (MultiValueDict, multiValueDictResolver))
+        # it should go before dict
+    except ImportError:
+        pass  # django may not be installed
 
 
 def getType(obj):
--- a/Debugger/VariablesViewer.py	Fri Sep 16 19:34:58 2016 +0200
+++ b/Debugger/VariablesViewer.py	Mon Sep 19 20:10:33 2016 +0200
@@ -588,6 +588,10 @@
             else:
                 return SpecialVarItem(parent, dvar, dvalue, dtype,
                                       self.framenr, self.__globalScope)
+        elif dtype in ["numpy.ndarray", "django.MultiValueDict"]:
+            return SpecialVarItem(
+                parent, dvar, self.tr("{0} items").format(dvalue), dtype,
+                self.framenr, self.__globalScope)
         else:
             if self.dvar_rx_array_element.exactMatch(dvar):
                 return ArrayElementVarItem(parent, dvar, dvalue, dtype)
@@ -699,7 +703,11 @@
         name = VariableItem.extractIndicators(itm.text(0).strip())[0]
         
         par = itm.parent()
-        nlist = [name]
+        if name.startswith("["):    # numpy.ndarray
+            nlist = []
+        else:
+            nlist = [name]
+        
         # build up the fully qualified name
         while par is not None:
             pname, indicators = VariableItem.extractIndicators(
@@ -709,9 +717,20 @@
                     nlist[0] = '[{0}].'.format(nlist[0][:-1])
                 else:
                     nlist[0] = '[{0}]'.format(nlist[0])
-                nlist.insert(0, pname)
+                if not pname.startswith("["):   # numpy.ndarray
+                    nlist.insert(0, pname)
             else:
-                nlist.insert(0, '{0}.'.format(pname))
+                if par.text(2) == "django.MultiValueDict":
+                    nlist[0] = 'getlist({0})'.format(nlist[0])
+                elif par.text(2) == "numpy.ndarray":
+                    if nlist[0][0].isalpha():
+                        if nlist[0] in ["min", "max", "mean"]:
+                            nlist[0] = ".{0}()".format(nlist[0])
+                        else:
+                            nlist[0] = ".{0}".format(nlist[0])
+                    nlist.insert(0, pname)
+                else:
+                    nlist.insert(0, '{0}.'.format(pname))
             par = par.parent()
             
         name = ''.join(nlist)

eric ide

mercurial