eric6/DebugClients/Python/DebugClientBase.py

branch
Variables Viewer
changeset 6969
fd7af2312383
parent 6942
2602857055c5
child 6971
77cf9a30562d
diff -r c634f51e40ec -r fd7af2312383 eric6/DebugClients/Python/DebugClientBase.py
--- a/eric6/DebugClients/Python/DebugClientBase.py	Sun Apr 21 17:27:52 2019 +0200
+++ b/eric6/DebugClients/Python/DebugClientBase.py	Sun Apr 21 21:20:24 2019 +0200
@@ -26,7 +26,7 @@
 import DebugVariables
 from DebugBase import setRecursionLimit, printerr   # __IGNORE_WARNING__
 from AsyncFile import AsyncFile, AsyncPendingWrite
-from DebugConfig import ConfigVarTypeStrings
+from DebugConfig import ConfigQtNames, ConfigVarTypeStrings
 from FlexCompleter import Completer
 from DebugUtilities import prepareJsonCommand
 from BreakpointWatch import Breakpoint, Watch
@@ -379,14 +379,12 @@
         
         if method == "RequestVariables":
             self.__dumpVariables(
-                params["frameNumber"], params["scope"], params["filters"],
-                params["maxSize"])
+                params["frameNumber"], params["scope"], params["filters"])
         
         elif method == "RequestVariable":
             self.__dumpVariable(
                 params["variable"], params["frameNumber"],
-                params["scope"], params["filters"],
-                params["maxSize"])
+                params["scope"], params["filters"])
         
         elif method == "RequestThreadList":
             self.dumpThreadList()
@@ -1429,7 +1427,7 @@
         # reset coding
         self.__coding = self.defaultCoding
 
-    def __dumpVariables(self, frmnr, scope, filterList, maxSize):
+    def __dumpVariables(self, frmnr, scope, filterList):
         """
         Private method to return the variables of a frame to the debug server.
         
@@ -1447,6 +1445,7 @@
         if self.currentThread is None:
             return
         
+        self.resolverCache = [{}, {}]
         frmnr += self.currentThread.skipFrames
         if scope == 0:
             self.framenr = frmnr
@@ -1468,22 +1467,18 @@
             scope = -1
         else:
             varDict = f.f_locals
-            
-        varlist = []
         
-        if scope != -1:
-            keylist = varDict.keys()
-            
-            vlist = self.__formatVariablesList(
-                keylist, varDict, scope, filterList, maxSize=maxSize)
-            varlist.extend(vlist)
+        if scope == -1:
+            varlist = []
+        else:
+            varlist = self.__formatVariablesList(varDict, scope, filterList)
         
         self.sendJsonCommand("ResponseVariables", {
             "scope": scope,
             "variables": varlist,
         })
     
-    def __dumpVariable(self, var, frmnr, scope, filterList, maxSize):
+    def __dumpVariable(self, var, frmnr, scope, filterList):
         """
         Private method to return the variables of a frame to the debug server.
         
@@ -1523,12 +1518,16 @@
         
         varlist = []
         
-        if scope != -1:
+        if scope != -1 and str(var) in self.resolverCache[scope]:
+            varGen = self.resolverCache[scope][str(var)]
+            idx, varDict = next(varGen)
+            var.insert(0, idx)
+            varlist = self.__formatVariablesList(varDict, scope, filterList)
+        elif scope != -1:
             variable = varDict
+            # Lookup the wanted attribute
             for attribute in var:
-                attribute = self.__extractIndicators(attribute)[0]
-                typeObject, typeName, typeStr, resolver = \
-                    DebugVariables.getType(variable)
+                _, _, resolver = DebugVariables.getType(variable)
                 if resolver:
                     variable = resolver.resolve(variable, attribute)
                     if variable is None:
@@ -1536,26 +1535,35 @@
                     
                 else:
                     break
-                
+            
+            idx = -2
+            # If found, get the details of attribute
             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)
+                typeName, typeStr, resolver = DebugVariables.getType(variable)
+                if typeStr.startswith(ConfigQtNames):
+                    # Gently handle exception which could occure as special
+                    # cases, e.g. already deleted C++ objects, str conversion..
+                    try:
+                        varlist = self.__formatQtVariable(variable, typeName)
+                    except Exception:
+                        varlist = []
+                    idx = -1
                 elif resolver:
-                    varDict = resolver.getDictionary(variable)
-                    vlist = self.__formatVariablesList(
-                        list(varDict.keys()), varDict, scope, filterList,
-                        maxSize=maxSize)
-                    varlist.extend(vlist)
+                    varGen = resolver.getDictionary(variable)
+                    self.resolverCache[scope][str(var)] = varGen
+                    
+                    idx, varDict = next(varGen)
+                    varlist = self.__formatVariablesList(
+                        varDict, scope, filterList)
+            
+            var.insert(0, idx)
         
         self.sendJsonCommand("ResponseVariable", {
             "scope": scope,
             "variable": var,
             "variables": varlist,
         })
-        
+    
     def __extractIndicators(self, var):
         """
         Private method to extract the indicator string from a variable text.
@@ -1702,7 +1710,7 @@
             varlist.append(("data", "str", "{0}".format(value.data())))
         elif qttype == 'QDomComment':
             varlist.append(("data", "str", "{0}".format(value.data())))
-        elif qttype == "QDomDocument":
+        elif qttype == 'QDomDocument':
             varlist.append(("text", "str", "{0}".format(value.toString())))
         elif qttype == 'QDomElement':
             varlist.append(("tagName", "str", "{0}".format(value.tagName())))
@@ -1715,10 +1723,14 @@
             varlist.append(
                 ("address", "QHostAddress", "{0}".format(value.toString())))
             
+        # PySide specific
+        elif qttype == 'EnumType':  # Not in PyQt possible
+            for key, value in value.values.items():
+                varlist.append((key, qttype, "{0}".format(int(value))))
+        
         return varlist
     
-    def __formatVariablesList(self, keylist, dict_, scope, filterList=None,
-                              formatSequences=False, maxSize=0):
+    def __formatVariablesList(self, dict_, scope, filterList=None):
         """
         Private method to produce a formated variables list.
         
@@ -1728,8 +1740,6 @@
         expressions. The formated variables list (a list of tuples of 3
         values) is returned.
         
-        @param keylist keys of the dictionary to be formatted
-        @type list of str
         @param dict_ the dictionary to be scanned
         @type dict
         @param scope 1 to filter using the globals filter, 0 using the locals
@@ -1741,14 +1751,6 @@
             Variables are only added to the list, if their type is not
             contained in the filter list.
         @type list of int
-        @param formatSequences flag indicating, that sequence or dictionary
-            variables should be formatted. If it is 0 (or false), just the
-            number of items contained in these variables is returned.
-        @type bool
-        @param maxSize maximum size the formatted value of a variable will
-            be shown. If it is bigger than that, a 'too big' indication will
-            be placed in the value field.
-        @type int
         @return A tuple consisting of a list of formatted variables. Each
             variable entry is a tuple of three elements, the variable name,
             its type and value.
@@ -1761,8 +1763,14 @@
             patternFilterObjects = self.globalsFilterObjects
         else:
             patternFilterObjects = self.localsFilterObjects
+        if type(dict_) == dict:
+            dict_ = dict_.items()
         
-        for key in keylist:
+        for key, value in dict_:
+            # no more elements available
+            if key == -2:
+                break
+            
             # filter based on the filter pattern
             matched = False
             for pat in patternFilterObjects:
@@ -1773,9 +1781,7 @@
                 continue
             
             # filter hidden attributes (filter #0)
-            if 0 in filterList and str(key)[:2] == '__' and not (
-                key == "___len___" and
-                    DebugVariables.TooLargeAttribute in keylist):
+            if 0 in filterList and str(key)[:2] == '__':
                 continue
             
             # special handling for '__builtins__' (it's way too big)
@@ -1783,67 +1789,57 @@
                 rvalue = '<module __builtin__ (built-in)>'
                 valtype = 'module'
             else:
-                value = dict_[key]
                 valtypestr = str(type(value))[1:-1]
                 _, valtype = valtypestr.split(' ', 1)
                 valtype = valtype[1:-1]
+                # Strip 'instance' to be equal with Python 3
+                if valtype == "instancemethod":
+                    valtype = "method"
+                
                 valtypename = type(value).__name__
-                if valtype not in ConfigVarTypeStrings:
-                    if valtype in ["numpy.ndarray", "array.array"]:
+                try:
+                    if ConfigVarTypeStrings.index(valtype) in filterList:
+                        continue
+                except ValueError:
+                    if valtype == "classobj":
+                        if ConfigVarTypeStrings.index(
+                                'instance') in filterList:
+                            continue
+                    elif valtype == "sip.methoddescriptor":
+                        if ConfigVarTypeStrings.index('method') in filterList:
+                            continue
+                    elif valtype == "sip.enumtype":
+                        if ConfigVarTypeStrings.index('class') in filterList:
+                            continue
+                    elif not valtype.startswith(("PySide.", "PySide2.")) and \
+                        (ConfigVarTypeStrings.index('other') in
+                         filterList):
+                        continue
+                    elif valtype in ["numpy.ndarray", "array.array"]:
                         if ConfigVarTypeStrings.index('list') in filterList:
                             continue
                     elif valtypename == "MultiValueDict":
                         if ConfigVarTypeStrings.index('dict') in filterList:
                             continue
-                    elif valtype == "sip.methoddescriptor":
-                        if ConfigVarTypeStrings.index(
-                                'method') in filterList:
-                            continue
-                    elif valtype == "sip.enumtype":
-                        if ConfigVarTypeStrings.index('class') in filterList:
-                            continue
-                    elif ConfigVarTypeStrings.index('instance') in filterList:
-                        continue
                     
                     if (not valtypestr.startswith('type ') and
                             valtypename not in
-                            ["ndarray", "MultiValueDict", "array"]):
+                            ["ndarray", "MultiValueDict", "array"] and
+                            not valtype.startswith(('PyQt5.', 'PyQt4.'))):
                         valtype = valtypestr
-                else:
-                    try:
-                        # Strip 'instance' to be equal with Python 3
-                        if valtype == "instancemethod":
-                            valtype = "method"
-                        
-                        if ConfigVarTypeStrings.index(valtype) in filterList:
-                            continue
-                    except ValueError:
-                        if valtype == "classobj":
-                            if ConfigVarTypeStrings.index(
-                                    'instance') in filterList:
-                                continue
-                        elif valtype == "sip.methoddescriptor":
-                            if ConfigVarTypeStrings.index(
-                                    'method') in filterList:
-                                continue
-                        elif valtype == "sip.enumtype":
-                            if ConfigVarTypeStrings.index('class') in \
-                                    filterList:
-                                continue
-                        elif not valtype.startswith("PySide") and \
-                            (ConfigVarTypeStrings.index('other') in
-                             filterList):
-                            continue
                 
                 try:
-                    if valtype in ['list', 'tuple', 'dict', 'set',
-                                   'frozenset', 'array.array']:
-                        if valtype == 'dict':
-                            rvalue = "{0:d}".format(len(value.keys()))
-                        else:
-                            rvalue = "{0:d}".format(len(value))
+                    if valtype in ['list', 'tuple', 'dict', 'set', 'frozenset'
+                                   ]:
+                        rvalue = "{0:d}".format(len(value))
+                    elif valtype == 'array.array':
+                        rvalue = "{0:d}|{1}".format(
+                            len(value), value.typecode)
+                    elif valtype == 'collections.defaultdict':
+                        rvalue = "{0:d}|{1}".format(
+                            len(value), value.default_factory)
                     elif valtype == "numpy.ndarray":
-                        rvalue = "{0:d}".format(value.size)
+                        rvalue = "x".join(str(x) for x in value.shape)
                     elif valtypename == "MultiValueDict":
                         rvalue = "{0:d}".format(len(value.keys()))
                         valtype = "django.MultiValueDict"  # shortened type
@@ -1852,16 +1848,12 @@
                         if valtype.startswith('class') and \
                            rvalue[0] in ['{', '(', '[']:
                             rvalue = ""
-                        elif maxSize and len(rvalue) > maxSize:
-                            rvalue = "@@TOO_BIG_TO_SHOW@@"
+                        elif (rvalue.startswith("<class '") and
+                                valtype.startswith(ConfigQtNames)):
+                            rvalue = rvalue[8:-2]
                 except Exception:
                     rvalue = ''
             
-            if formatSequences:
-                if str(key) == key:
-                    key = "'{0!s}'".format(key)
-                else:
-                    key = str(key)
             varlist.append((key, valtype, rvalue))
         
         return varlist

eric ide

mercurial