Merged with recent changes provided by Tobias. eric7

Wed, 01 Sep 2021 19:54:34 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 01 Sep 2021 19:54:34 +0200
branch
eric7
changeset 8569
6dfc6a3ad31f
parent 8567
a9ec6702c664 (current diff)
parent 8568
890dfe038613 (diff)
child 8570
65ec02bfa9d2

Merged with recent changes provided by Tobias.

--- a/eric7/DebugClients/Python/DebugClientBase.py	Wed Sep 01 19:42:43 2021 +0200
+++ b/eric7/DebugClients/Python/DebugClientBase.py	Wed Sep 01 19:54:34 2021 +0200
@@ -27,7 +27,7 @@
 import DebugVariables
 from DebugBase import setRecursionLimit, printerr   # __IGNORE_WARNING__
 from AsyncFile import AsyncFile, AsyncPendingWrite
-from DebugConfig import ConfigQtNames, SpecialAttributes
+from DebugConfig import SpecialAttributes, NonExpandableTypes
 from FlexCompleter import Completer
 from DebugUtilities import prepareJsonCommand
 from BreakpointWatch import Breakpoint, Watch
@@ -126,11 +126,17 @@
     """
     clientCapabilities = DebugClientCapabilities.HasAll
     
-    # keep these in sync with VariablesViewer.VariableItem.Indicators
-    Indicators = ("()", "[]", "{:}", "{}")      # __IGNORE_WARNING_M613__
-    arrayTypes = {
-        'list', 'tuple', 'dict', 'set', 'frozenset', "class 'dict_items'",
-        "class 'dict_keys'", "class 'dict_values'"
+    Type2Indicators = {
+        # Python types
+        'list': '[]',
+        'tuple': '()',
+        'dict': '{:}',                          # __IGNORE_WARNING_M613__
+        'set': '{}',                            # __IGNORE_WARNING_M613__
+        'frozenset': '{}',                      # __IGNORE_WARNING_M613__
+        'numpy.ndarray': '[ndarray]',           # __IGNORE_WARNING_M613__
+        'collections.abc.ItemsView': '[]',
+        'collections.abc.KeysView': '[]',
+        'collections.abc.ValuesView': '[]',
     }
     
     def __init__(self):
@@ -151,9 +157,9 @@
         # The list of complete lines to execute.
         self.buffer = ''
         
-        # The list of regexp objects to filter variables against
-        self.globalsFilterObjects = []
-        self.localsFilterObjects = []
+        # The precompiled regexp to filter variables against
+        self.globalsFilterObjects = None
+        self.localsFilterObjects = None
 
         self._fncache = {}
         self.dircache = []
@@ -1520,8 +1526,11 @@
         else:
             varDict = f.f_locals
         
+        # Update known types list
+        DebugVariables.updateTypeMap()
+        
         varlist = [] if scope < 0 else self.__formatVariablesList(
-            varDict, scope, filterList)
+            varDict.items(), scope, filterList)
         
         self.sendJsonCommand("ResponseVariables", {
             "scope": scope,
@@ -1565,16 +1574,19 @@
         
         varlist = []
         
+        # fast path if variable was looked up before (see elif)
         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)
+            if idx != -2:  # more elements available
+                var.insert(0, idx)
+                varlist = self.__formatVariablesList(
+                    varDict, scope, filterList)
         elif scope != -1:
             variable = varDict
             # Lookup the wanted attribute
             for attribute in var:
-                _, _, resolver = DebugVariables.getType(variable)
+                resolver = DebugVariables.getResolver(variable)
                 if resolver:
                     variable = resolver.resolve(variable, attribute)
                     if variable is None:
@@ -1586,22 +1598,16 @@
             idx = -3  # Requested variable doesn't exist anymore
             # If found, get the details of attribute
             if variable is not None:
-                typeName, typeStr, resolver = DebugVariables.getType(variable)
+                resolver = DebugVariables.getResolver(variable)
                 if resolver:
-                    varGen = resolver.getDictionary(variable)
+                    varGen = resolver.getVariableList(variable)
+                    # cache for next lookup
                     self.resolverCache[scope][str(var)] = varGen
                     
                     idx, varDict = next(varGen)
-                    varlist = self.__formatVariablesList(
-                        varDict, scope, filterList)
-                else:
-                    # Gently handle exception which could occur as special
-                    # cases, e.g. already deleted C++ objects, str conversion..
-                    try:
-                        varlist = self.__formatQtVariable(variable, typeName)
-                    except Exception:
-                        varlist = []
-                    idx = -1
+                    if idx != -2:  # more elements available
+                        varlist = self.__formatVariablesList(
+                            varDict, scope, filterList)
             
             var.insert(0, idx)
         
@@ -1611,169 +1617,7 @@
             "variables": varlist,
         })
     
-    def __extractIndicators(self, var):
-        """
-        Private method to extract the indicator string from a variable text.
-        
-        @param var variable text
-        @type str
-        @return tuple containing the variable text without indicators and the
-            indicator string
-        @rtype tuple of two str
-        """
-        for indicator in DebugClientBase.Indicators:
-            if var.endswith(indicator):
-                return var[:-len(indicator)], indicator
-        
-        return var, ""
-        
-    def __formatQtVariable(self, value, qttype):
-        """
-        Private method to produce a formatted output of a simple Qt5/Qt6 type.
-        
-        @param value variable to be formatted
-        @param qttype type of the Qt variable to be formatted (string)
-        @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.
-        """
-        varlist = []
-        if qttype == 'QChar':
-            varlist.append(
-                ("", "QChar", "{0}".format(chr(value.unicode()))))
-            varlist.append(("", "int", "{0:d}".format(value.unicode())))
-        elif qttype == 'QByteArray':
-            varlist.append(
-                ("bytes", "QByteArray", "{0}".format(bytes(value))[2:-1]))
-            varlist.append(
-                ("hex", "QByteArray", "{0}".format(value.toHex())[2:-1]))
-            varlist.append(
-                ("base64", "QByteArray", "{0}".format(value.toBase64())[2:-1]))
-            varlist.append(("percent encoding", "QByteArray",
-                            "{0}".format(value.toPercentEncoding())[2:-1]))
-        elif qttype == 'QString':
-            varlist.append(("", "QString", "{0}".format(value)))
-        elif qttype == 'QStringList':
-            for i in range(value.count()):
-                varlist.append(
-                    ("{0:d}".format(i), "QString", "{0}".format(value[i])))
-        elif qttype == 'QPoint':
-            varlist.append(("x", "int", "{0:d}".format(value.x())))
-            varlist.append(("y", "int", "{0:d}".format(value.y())))
-        elif qttype == 'QPointF':
-            varlist.append(("x", "float", "{0:g}".format(value.x())))
-            varlist.append(("y", "float", "{0:g}".format(value.y())))
-        elif qttype == 'QRect':
-            varlist.append(("x", "int", "{0:d}".format(value.x())))
-            varlist.append(("y", "int", "{0:d}".format(value.y())))
-            varlist.append(("width", "int", "{0:d}".format(value.width())))
-            varlist.append(("height", "int", "{0:d}".format(value.height())))
-        elif qttype == 'QRectF':
-            varlist.append(("x", "float", "{0:g}".format(value.x())))
-            varlist.append(("y", "float", "{0:g}".format(value.y())))
-            varlist.append(("width", "float", "{0:g}".format(value.width())))
-            varlist.append(("height", "float", "{0:g}".format(value.height())))
-        elif qttype == 'QSize':
-            varlist.append(("width", "int", "{0:d}".format(value.width())))
-            varlist.append(("height", "int", "{0:d}".format(value.height())))
-        elif qttype == 'QSizeF':
-            varlist.append(("width", "float", "{0:g}".format(value.width())))
-            varlist.append(("height", "float", "{0:g}".format(value.height())))
-        elif qttype == 'QColor':
-            varlist.append(("name", "str", "{0}".format(value.name())))
-            r, g, b, a = value.getRgb()
-            varlist.append(
-                ("rgba", "int",
-                 "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a)))
-            h, s, v, a = value.getHsv()
-            varlist.append(
-                ("hsva", "int",
-                 "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a)))
-            c, m, y, k, a = value.getCmyk()
-            varlist.append(
-                ("cmyka", "int",
-                 "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a)))
-        elif qttype == 'QDate':
-            varlist.append(("", "QDate", "{0}".format(value.toString())))
-        elif qttype == 'QTime':
-            varlist.append(("", "QTime", "{0}".format(value.toString())))
-        elif qttype == 'QDateTime':
-            varlist.append(("", "QDateTime", "{0}".format(value.toString())))
-        elif qttype == 'QDir':
-            varlist.append(("path", "str", "{0}".format(value.path())))
-            varlist.append(("absolutePath", "str",
-                            "{0}".format(value.absolutePath())))
-            varlist.append(("canonicalPath", "str",
-                            "{0}".format(value.canonicalPath())))
-        elif qttype == 'QFile':
-            varlist.append(("fileName", "str", "{0}".format(value.fileName())))
-        elif qttype == 'QFont':
-            varlist.append(("family", "str", "{0}".format(value.family())))
-            varlist.append(
-                ("pointSize", "int", "{0:d}".format(value.pointSize())))
-            varlist.append(("weight", "int", "{0:d}".format(value.weight())))
-            varlist.append(("bold", "bool", "{0}".format(value.bold())))
-            varlist.append(("italic", "bool", "{0}".format(value.italic())))
-        elif qttype == 'QUrl':
-            varlist.append(("url", "str", "{0}".format(value.toString())))
-            varlist.append(("scheme", "str", "{0}".format(value.scheme())))
-            varlist.append(("user", "str", "{0}".format(value.userName())))
-            varlist.append(("password", "str", "{0}".format(value.password())))
-            varlist.append(("host", "str", "{0}".format(value.host())))
-            varlist.append(("port", "int", "{0:d}".format(value.port())))
-            varlist.append(("path", "str", "{0}".format(value.path())))
-        elif qttype == 'QModelIndex':
-            varlist.append(("valid", "bool", "{0}".format(value.isValid())))
-            if value.isValid():
-                varlist.append(("row", "int", "{0}".format(value.row())))
-                varlist.append(("column", "int", "{0}".format(value.column())))
-                varlist.append(
-                    ("internalId", "int", "{0}".format(value.internalId())))
-                varlist.append(("internalPointer", "void *",
-                                "{0}".format(value.internalPointer())))
-        elif qttype in ('QRegExp', "QRegularExpression"):
-            varlist.append(("pattern", "str", "{0}".format(value.pattern())))
-        
-        # GUI stuff
-        elif qttype == 'QAction':
-            varlist.append(("name", "str", "{0}".format(value.objectName())))
-            varlist.append(("text", "str", "{0}".format(value.text())))
-            varlist.append(
-                ("icon text", "str", "{0}".format(value.iconText())))
-            varlist.append(("tooltip", "str", "{0}".format(value.toolTip())))
-            varlist.append(
-                ("whatsthis", "str", "{0}".format(value.whatsThis())))
-            varlist.append(
-                ("shortcut", "str",
-                 "{0}".format(value.shortcut().toString())))
-        elif qttype == 'QKeySequence':
-            varlist.append(("value", "", "{0}".format(value.toString())))
-            
-        # XML stuff
-        elif qttype == 'QDomAttr':
-            varlist.append(("name", "str", "{0}".format(value.name())))
-            varlist.append(("value", "str", "{0}".format(value.value())))
-        elif qttype in ('QDomCharacterData', 'QDomComment', 'QDomText'):
-            varlist.append(("data", "str", "{0}".format(value.data())))
-        elif qttype == 'QDomDocument':
-            varlist.append(("text", "str", "{0}".format(value.toString())))
-        elif qttype == 'QDomElement':
-            varlist.append(("tagName", "str", "{0}".format(value.tagName())))
-            varlist.append(("text", "str", "{0}".format(value.text())))
-        
-        # Networking stuff
-        elif qttype == 'QHostAddress':
-            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, dict_, scope, filterList=None):
+    def __formatVariablesList(self, variables, scope, filterList=None):
         """
         Private method to produce a formated variables list.
         
@@ -1799,7 +1643,7 @@
             its type and value.
         @rtype list of tuple of (str, str, str)
         """
-        filterList = [] if filterList is None else filterList[:]
+        filterList = set(filterList or [])
         
         varlist = []
         patternFilterObjects = (
@@ -1807,27 +1651,26 @@
             if scope else
             self.localsFilterObjects
         )
-        if type(dict_) == dict:
-            dict_ = dict_.items()
         
-        for key, value in dict_:
-            # no more elements available
-            if key == -2:
-                break
+        for variabel in variables:
+            valtype = None
+            rvalue = None
+            try:
+                key, value = variabel
+            except ValueError:
+                # Special case for some Qt variables, where the real type is
+                # overwritten
+                key, valtype, rvalue = variabel
             
             # filter based on the filter pattern
-            matched = False
-            for pat in patternFilterObjects:
-                if pat.match(str(key)):
-                    matched = True
-                    break
-            if matched:
+            if patternFilterObjects and patternFilterObjects.match(str(key)):
                 continue
             
             # filter hidden attributes (filter #0)
             if '__' in filterList and str(key)[:2] == '__':
                 continue
             
+            hasChildren = False
             # special handling for '__builtins__' (it's way too big)
             if key == '__builtins__':
                 rvalue = '<module builtins (built-in)>'
@@ -1841,67 +1684,92 @@
                  "builtin_function_or_method" in filterList)
             ):
                 continue
-            else:
-                isQt = False
+            elif valtype is None:
                 # valtypestr, e.g. class 'PyQt6.QtCore.QPoint'
-                valtypestr = str(type(value))[1:-1]
+                valtypestr = str(type(value))
                 _, valtype = valtypestr.split(' ', 1)
-                # valtype, e.g. PyQt6.QtCore.QPoint
-                valtype = valtype[1:-1]
+                # valtype is the real type, e.g. PyQt6.QtCore.QPoint
+                # valtype_filter is used for filtering, where the base class is
+                # also important
+                valtype = valtype_filter = valtype[1:-2]
                 # Strip 'instance' to be equal with Python 3
                 if valtype == "instancemethod":
-                    valtype = "method"
-                elif valtype in ("type", "classobj"):
-                    valtype = "class"
+                    valtype = valtype_filter = "method"
+                elif isinstance(value, type):
+                    valtype_filter = "class"
+                    if valtype == "type":
+                        valtype = "class"
                 elif valtype == "method-wrapper":
-                    valtype = "builtin_function_or_method"
+                    valtype = valtype_filter = "builtin_function_or_method"
                 
-                # valtypename, e.g. QPoint
-                valtypename = type(value).__name__
+                # Don't process variables which types are on filter list
                 if (
-                    valtype in filterList or
-                    (valtype in ("sip.enumtype", "sip.wrappertype") and
+                    valtype_filter in filterList or
+                    (valtype_filter in ("sip.enumtype", "sip.wrappertype") and
                      'class' in filterList) or
-                    (valtype in (
+                    (valtype_filter in (
                         "sip.methoddescriptor", "method_descriptor") and
                      'method' in filterList) or
-                    (valtype in ("numpy.ndarray", "array.array") and
+                    (valtype_filter in ("numpy.ndarray", "array.array") and
                      'list' in filterList) or
-                    (valtypename == "MultiValueDict" and
+                    (valtype_filter == "django.MultiValueDict" and
                      'dict' in filterList) or
                     'instance' in filterList
                 ):
                     continue
-                
-                isQt = valtype.startswith(ConfigQtNames)
+            
+            length = -2
+            indicator = ''
+            
+            if valtype == 'str':
+                rvalue = repr(value)
+                length = len(rvalue)
+            elif valtype in NonExpandableTypes:
+                rvalue = repr(value)
+            
+            if rvalue is not None:
+                varlist.append(
+                    (key, indicator, valtype, hasChildren, length, rvalue)
+                )
+                continue
+            
+            try:
+                for dtype in DebugVariables._ArrayTypes:
+                    if isinstance(value, dtype):
+                        try:
+                            length = len(value)
+                        except TypeError:
+                            length = -1  # Uninitialized array
+                        
+                        dtype = str(dtype)[8:-2]
+                        # Standard array type indicators
+                        indicator = self.Type2Indicators.get(dtype, '')
+                        
+                        # Special handling of some array types
+                        if valtype == 'array.array':
+                            indicator = '[<{0}>]'.format(value.typecode)
+                        elif valtype == 'collections.defaultdict':
+                            if value.default_factory is None:
+                                def_factory = "None"
+                            else:
+                                def_factory = value.default_factory.__name__
+                            indicator = '{{:<{0}>}}'.format(def_factory)
+                        elif valtype == "numpy.ndarray" and length > -1:
+                            length = "x".join(str(x) for x in value.shape)
+                        elif valtype.endswith(".MultiValueDict"):
+                            indicator = "{:}"
+                            valtype = "django.MultiValueDict"  # shortened type
+                        break
+                else:
+                    rvalue = repr(value)
                 
-                try:
-                    if valtype in self.arrayTypes:
-                        rvalue = "{0:d}".format(len(value))
-                    elif valtype == 'array.array':
-                        rvalue = "{0:d}|{1}".format(
-                            len(value), value.typecode)
-                    elif valtype == 'collections.defaultdict':
-                        if value.default_factory is None:
-                            factoryName = "None"
-                        else:
-                            factoryName = value.default_factory.__name__
-                        rvalue = "{0:d}|{1}".format(len(value), factoryName)
-                    elif valtype == "numpy.ndarray":
-                        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
-                    else:
-                        rvalue = repr(value)
-                        if valtype.startswith('class') and rvalue[0] in '{([':
-                            rvalue = ""
-                        elif (isQt and rvalue.startswith("<class '")):
-                            rvalue = rvalue[8:-2]
-                except Exception:
-                    rvalue = ''
-            
-            varlist.append((key, valtype, rvalue))
+                hasChildren = True
+            except Exception:
+                rvalue = ''
+        
+            varlist.append(
+                (key, indicator, valtype, hasChildren, length, rvalue)
+            )
         
         return varlist
     
@@ -1913,13 +1781,18 @@
             variables (int)
         @param filterString string of filter patterns separated by ';'
         """
-        patternFilterObjects = []
-        for pattern in filterString.split(';'):
-            patternFilterObjects.append(re.compile('^{0}$'.format(pattern)))
+        patternFilterObjects = None
+        if filterString.strip():
+            pattern = filterString.replace(';', '|')
+            try:
+                patternFilterObjects = re.compile(pattern)
+            except re.error:
+                pass
+        
         if scope:
-            self.globalsFilterObjects = patternFilterObjects[:]
+            self.globalsFilterObjects = patternFilterObjects
         else:
-            self.localsFilterObjects = patternFilterObjects[:]
+            self.localsFilterObjects = patternFilterObjects
     
     def __completionList(self, text):
         """
--- a/eric7/DebugClients/Python/DebugConfig.py	Wed Sep 01 19:42:43 2021 +0200
+++ b/eric7/DebugClients/Python/DebugConfig.py	Wed Sep 01 19:54:34 2021 +0200
@@ -12,15 +12,24 @@
     "__bases__", "__class__", "__dict__", "__doc__", "__mro__", "__name__",
     "__qualname__",
 )
+
 BatchSize = 200
 ConfigQtNames = (
     'PyQt5.', 'PyQt6.', 'PySide2.', 'PySide6.', 'Shiboken.EnumType'
 )
+
 ConfigKnownQtTypes = (
-    '.QChar', '.QByteArray', '.QString', '.QStringList', '.QPoint', '.QPointF',
+    '.QByteArray', '.QPoint', '.QPointF', '.QLabel', '.QPushButton',
     '.QRect', '.QRectF', '.QSize', '.QSizeF', '.QColor', '.QDate', '.QTime',
     '.QDateTime', '.QDir', '.QFile', '.QFont', '.QUrl', '.QModelIndex',
     '.QRegExp', '.QRegularExpression', '.QAction', '.QKeySequence',
     '.QDomAttr', '.QDomCharacterData', '.QDomComment', '.QDomDocument',
-    '.QDomElement', '.QDomText', '.QHostAddress', '.EnumType'
+    '.QDomElement', '.QDomText', '.QHostAddress', '.EnumType',
 )
+
+NonExpandableTypes = (
+    'int', 'float', 'bool', 'NoneType', 'bytes', 'function', 'object',
+    'builtin_function_or_method', 'classmethod_descriptor', 'weakref',
+    'wrapper_descriptor', 'method_descriptor', 'property', 'method',
+    'getset_descriptor', 'member_descriptor',
+)
--- a/eric7/DebugClients/Python/DebugVariables.py	Wed Sep 01 19:42:43 2021 +0200
+++ b/eric7/DebugClients/Python/DebugVariables.py	Wed Sep 01 19:54:34 2021 +0200
@@ -8,6 +8,9 @@
 """
 
 import contextlib
+import sys
+
+from collections.abc import ItemsView, KeysView, ValuesView
 
 from DebugConfig import ConfigQtNames, ConfigKnownQtTypes, BatchSize
 
@@ -16,7 +19,7 @@
 #
 
 ############################################################
-## Classes implementing resolvers for various compund types
+## Classes implementing resolvers for various compound types
 ############################################################
 
 
@@ -37,24 +40,20 @@
         """
         return getattr(var, attribute, None)
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @return dictionary containing the variable attributes
-        @rtype dict
+        @return list containing the variable attributes
+        @rtype list
         """
-        names = dir(var)
-        if not names and hasattr(var, "__members__"):
-            names = var.__members__
-        
-        d = {}
-        for name in names:
+        d = []
+        for name in dir(var):
             with contextlib.suppress(Exception):
                 attribute = getattr(var, name)
-                d[name] = attribute
+                d.append((name, attribute))
         
         return d
 
@@ -68,29 +67,25 @@
     """
     Class used to resolve the default way.
     """
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        names = dir(var)
-        if not names and hasattr(var, "__members__"):
-            names = var.__members__
-        
-        d = {}
-        for name in names:
+        d = []
+        for name in dir(var):
             with contextlib.suppress(Exception):
                 attribute = getattr(var, name)
-                d[name] = attribute
+                d.append((name, attribute))
         
         yield -1, d
         while True:
-            yield -2, {}
+            yield -2, []
 
 
 ############################################################
@@ -144,17 +139,17 @@
 
         return key  # __IGNORE_WARNING_M834__
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        d = {}
+        d = []
         start = count = 0
         allItems = list(var.items())
         try:
@@ -166,23 +161,23 @@
         
         for key, value in allItems:
             key = "{0} (ID:{1})".format(self.keyToStr(key), id(key))
-            d[key] = value
+            d.append((key, value))
             count += 1
             if count >= BatchSize:
                 yield start, d
                 start += count
                 count = 0
-                d = {}
+                d = []
         
         if d:
             yield start, d
         
         # in case it has additional fields
-        d = super().getDictionary(var)
+        d = super().getVariableList(var)
         yield -1, d
         
         while True:
-            yield -2, {}
+            yield -2, []
 
 
 ############################################################
@@ -210,36 +205,36 @@
         except Exception:
             return getattr(var, str(attribute), None)
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        d = {}
+        d = []
         start = count = 0
         for idx, value in enumerate(var):
-            d[idx] = value
+            d.append((idx, value))
             count += 1
             if count >= BatchSize:
                 yield start, d
                 start = idx + 1
                 count = 0
-                d = {}
+                d = []
         
         if d:
             yield start, d
         
         # in case it has additional fields
-        d = super().getDictionary(var)
+        d = super().getVariableList(var)
         yield -1, d
         
         while True:
-            yield -2, {}
+            yield -2, []
     
 
 ############################################################
@@ -256,7 +251,7 @@
         Public method to get an attribute from a variable.
         
         @param var variable to extract an attribute or value from
-        @type tuple or list
+        @type dict_items, dict_keys or dict_values
         @param attribute id of the value to extract
         @type str
         @return value of the attribute
@@ -264,16 +259,17 @@
         """
         return super().resolve(list(var), attribute)
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @return dictionary containing the variable attributes
-        @rtype dict
+        @yield tuple containing the batch start index and a list
+            containing the variable attributes
+        @ytype tuple of (int, list)
         """
-        return super().getDictionary(list(var))
+        return super().getVariableList(list(var))
 
 
 ############################################################
@@ -309,36 +305,36 @@
         
         return None
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        d = {}
+        d = []
         start = count = 0
         for value in var:
             count += 1
-            d["'ID: {0}'".format(id(value))] = value
+            d.append(("'ID: {0}'".format(id(value)), value))
             if count >= BatchSize:
                 yield start, d
                 start += count
                 count = 0
-                d = {}
+                d = []
         
         if d:
             yield start, d
         
         # in case it has additional fields
-        additionals = super().getDictionary(var)
-        yield -1, additionals
+        d = super().getVariableList(var)
+        yield -1, d
         
         while True:
-            yield -2, {}
+            yield -2, []
     
 
 ############################################################
@@ -369,7 +365,7 @@
         Public method to get an attribute from a variable.
         
         @param var variable to extract an attribute or value from
-        @type tuple or list
+        @type ndarray
         @param attribute id of the value to extract
         @type str
         @return value of the attribute
@@ -400,17 +396,17 @@
         
         return None
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        d = {}
+        d = []
         start = count = 0
         try:
             len(var)  # Check if it's an unsized object, e.g. np.ndarray(())
@@ -419,45 +415,45 @@
             allItems = []
         
         for idx, value in enumerate(allItems):
-            d[str(idx)] = value
+            d.append((str(idx), value))
             count += 1
             if count >= BatchSize:
                 yield start, d
                 start += count
                 count = 0
-                d = {}
+                d = []
         
         if d:
             yield start, d
         
         # in case it has additional fields
-        d = super().getDictionary(var)
+        d = super().getVariableList(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')
-            d['mean'] = (
-                'ndarray too big, calculating mean would slow down debugging')
+            d.append(('min',
+                'ndarray too big, calculating min would slow down debugging'))
+            d.append(('max',
+                'ndarray too big, calculating max would slow down debugging'))
+            d.append(('mean',
+                'ndarray too big, calculating mean would slow down debugging'))
         elif self.__isNumeric(var):
             if var.size == 0:
-                d['min'] = 'empty array'
-                d['max'] = 'empty array'
-                d['mean'] = 'empty array'
+                d.append(('min', 'empty array'))
+                d.append(('max', 'empty array'))
+                d.append(('mean', 'empty array'))
             else:
-                d['min'] = var.min()
-                d['max'] = var.max()
-                d['mean'] = var.mean()
+                d.append(('min', var.min()))
+                d.append(('max', var.max()))
+                d.append(('mean', var.mean()))
         else:
-            d['min'] = 'not a numeric object'
-            d['max'] = 'not a numeric object'
-            d['mean'] = 'not a numeric object'
+            d.append(('min', 'not a numeric object'))
+            d.append(('max', 'not a numeric object'))
+            d.append(('mean', 'not a numeric object'))
         
         yield -1, d
         
         while True:
-            yield -2, {}
+            yield -2, []
 
 
 ############################################################
@@ -474,7 +470,7 @@
         Public method to get an attribute from a variable.
         
         @param var variable to extract an attribute or value from
-        @type dict
+        @type MultiValueDict
         @param attribute name of the attribute to extract
         @type str
         @return value of the attribute
@@ -493,17 +489,17 @@
         
         return None
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        d = {}
+        d = []
         start = count = 0
         allKeys = list(var.keys())
         try:
@@ -515,23 +511,23 @@
         
         for key in allKeys:
             dkey = "{0} (ID:{1})".format(self.keyToStr(key), id(key))
-            d[dkey] = var.getlist(key)
+            d.append((dkey, var.getlist(key)))
             count += 1
             if count >= BatchSize:
                 yield start, d
                 start += count
                 count = 0
-                d = {}
+                d = []
         
         if d:
             yield start, d
         
         # in case it has additional fields
-        d = super().getDictionary(var)
+        d = super(DictResolver, self).getVariableList(var)
         yield -1, d
         
         while True:
-            yield -2, {}
+            yield -2, []
     
 
 ############################################################
@@ -564,7 +560,7 @@
         Public method to get an attribute from a variable.
         
         @param var variable to extract an attribute or value from
-        @type tuple or list
+        @type array.array
         @param attribute id of the value to extract
         @type str
         @return value of the attribute
@@ -577,42 +573,179 @@
         
         return None
     
-    def getDictionary(self, var):
+    def getVariableList(self, var):
         """
-        Public method to get the attributes of a variable as a dictionary.
+        Public method to get the attributes of a variable as a list.
         
         @param var variable to be converted
         @type any
-        @yield tuple containing the batch start index and a dictionary
+        @yield tuple containing the batch start index and a list
             containing the variable attributes
-        @ytype tuple of (int, dict)
+        @ytype tuple of (int, list)
         """
-        d = {}
+        d = []
         start = count = 0
         allItems = var.tolist()
         
         for idx, value in enumerate(allItems):
-            d[str(idx)] = value
+            d.append((str(idx), value))
             count += 1
             if count >= BatchSize:
                 yield start, d
                 start += count
                 count = 0
-                d = {}
+                d = []
         
         if d:
             yield start, d
         
         # in case it has additional fields
-        d = super().getDictionary(var)
+        d = super().getVariableList(var)
         
         # Special data for array type: convert typecode to readable text
-        d['type'] = self.TypeCodeMap.get(var.typecode, 'illegal type')
+        d.append(('type', self.TypeCodeMap.get(var.typecode, 'illegal type')))
         
         yield -1, d
         
         while True:
-            yield -2, {}
+            yield -2, []
+
+
+############################################################
+## PySide / PyQt Resolver
+############################################################
+
+
+class QtResolver(BaseResolver):
+    """
+    Class used to resolve the Qt implementations.
+    """
+    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 Qt objects
+        @param attribute name of the attribute to extract
+        @type str
+        @return value of the attribute
+        @rtype any
+        """
+        if attribute == 'internalPointer':
+            return var.internalPointer()
+        
+        return getattr(var, attribute, None)
+    
+    def getVariableList(self, var):
+        """
+        Public method to get the attributes of a variable as a list.
+        
+        @param var variable to be converted
+        @type any
+        @yield tuple containing the batch start index and a list
+            containing the variable attributes
+        @ytype tuple of (int, list)
+        """
+        d = []
+        attributes = ()
+        # Gently handle exception which could occure as special
+        # cases, e.g. already deleted C++ objects, str conversion..
+        try:
+            qttype = type(var).__name__
+            
+            if qttype in ('QLabel', 'QPushButton'):
+                attributes = ('text', )
+            elif qttype == 'QByteArray':
+                d.append(('bytes', bytes(var)))
+                d.append(('hex', "QByteArray", "{0}".format(var.toHex())))
+                d.append(('base64', "QByteArray",
+                    "{0}".format(var.toBase64())))
+                d.append(('percent encoding', "QByteArray",
+                    "{0}".format(var.toPercentEncoding())))
+            elif qttype in ('QPoint', 'QPointF'):
+                attributes = ('x', 'y')
+            elif qttype in ('QRect', 'QRectF'):
+                attributes = ('x', 'y', 'width', 'height')
+            elif qttype in ('QSize', 'QSizeF'):
+                attributes = ('width', 'height')
+            elif qttype == 'QColor':
+                attributes = ('name', )
+                r, g, b, a = var.getRgb()
+                d.append(
+                    ('rgba', "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a))
+                )
+                h, s, v, a = var.getHsv()
+                d.append(
+                    ('hsva', "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a))
+                )
+                c, m, y, k, a = var.getCmyk()
+                d.append(
+                    ('cmyka',
+                    "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a))
+                )
+            elif qttype in ('QDate', 'QTime', 'QDateTime'):
+                d.append((qttype[1:].lower(), var.toString()))
+            elif qttype == 'QDir':
+                attributes = ('path', 'absolutePath', 'canonicalPath')
+            elif qttype == 'QFile':
+                attributes = ('fileName', )
+            elif qttype == 'QFont':
+                attributes = (
+                    'family', 'pointSize', 'weight', 'bold', 'italic'
+                )
+            elif qttype == 'QUrl':
+                d.append(('url', var.toString()))
+                attributes = ('scheme', 'userName', 'password', 'host', 'port',
+                              'path')
+            elif qttype == 'QModelIndex':
+                valid = var.isValid()
+                d.append(('valid', valid))
+                if valid:
+                    d.append(("internalPointer", var.internalPointer()))
+                    attributes = ('row', 'column', 'internalId')
+            elif qttype in ('QRegExp', "QRegularExpression"):
+                attributes = ('pattern', )
+                
+            # GUI stuff
+            elif qttype == 'QAction':
+                d.append(('shortcut', var.shortcut().toString()))
+                attributes = ('objectName', 'text', 'iconText', 'toolTip',
+                              'whatsThis')
+                
+            elif qttype == 'QKeySequence':
+                d.append(('keySequence', var.toString()))
+                
+            # XML stuff
+            elif qttype == 'QDomAttr':
+                attributes = ('name', 'var')
+            elif qttype in ('QDomCharacterData', 'QDomComment', 'QDomText'):
+                attributes = ('data', )
+            elif qttype == 'QDomDocument':
+                d.append(('text', var.toString()))
+            elif qttype == 'QDomElement':
+                attributes = ('tagName', 'text')
+                
+            # Networking stuff
+            elif qttype == 'QHostAddress':
+                d.append(('address', var.toString()))
+                
+            # PySide specific
+            elif qttype == 'EnumType':  # Not in PyQt possible
+                for key, value in var.values.items():
+                    d.append((key, int(value)))
+        except Exception:
+            pass
+        
+        for attribute in attributes:
+            d.append((attribute, getattr(var, attribute)()))
+        
+        # add additional fields
+        if qttype != 'EnumType':
+            d.extend(super().getVariableList(var))
+        
+        yield -1, d
+        while True:
+            yield -2, []
 
 
 defaultResolver = DefaultResolver()
@@ -623,13 +756,17 @@
 ndarrayResolver = NdArrayResolver()
 multiValueDictResolver = MultiValueDictResolver()
 arrayResolver = ArrayResolver()
+qtResolver = QtResolver()
+
 
 ############################################################
 ## Methods to determine the type of a variable and the
 ## resolver class to use
 ############################################################
 
-_TypeMap = None
+_TypeMap = _ArrayTypes = None
+_TryArray = _TryNumpy = _TryDjango = True
+_MapCount = 0
 
 
 def _initTypeMap():
@@ -638,77 +775,79 @@
     """
     global _TypeMap
     
+    # Type map for special handling of array types.
+    # All other types not listed here use the default resolver.
     _TypeMap = [
-        (type(None), None,),
-        (int, None),
-        (float, None),
-        (complex, None),
-        (str, None),
         (tuple, listResolver),
         (list, listResolver),
         (dict, dictResolver),
         (set, setResolver),
         (frozenset, setResolver),
+        (ItemsView, dictViewResolver),  # Since Python 3.0
+        (KeysView, dictViewResolver),
+        (ValuesView, dictViewResolver),
     ]
+
+
+# Initialize the static type map
+_initTypeMap()
+
+
+def updateTypeMap():
+    """
+    Public function to update the type map based on module imports.
+    """
+    global _TypeMap, _ArrayTypes, _TryArray, _TryNumpy, _TryDjango, _MapCount
     
-    with contextlib.suppress(Exception):
-        _TypeMap.append((long, None))           # __IGNORE_WARNING__
-
-    with contextlib.suppress(ImportError):
+    # array.array may not be imported (yet)
+    if _TryArray and 'array' in sys.modules:
         import array
         _TypeMap.append((array.array, arrayResolver))
-        # array.array may not be available
+        _TryArray = False
     
-    with contextlib.suppress(ImportError):
+    # numpy may not be imported (yet)
+    if _TryNumpy and 'numpy' in sys.modules:
         import numpy
         _TypeMap.append((numpy.ndarray, ndarrayResolver))
-        # numpy may not be installed
+        _TryNumpy = False
     
-    with contextlib.suppress(ImportError):
+    # django may not be imported (yet)
+    if _TryDjango and 'django' in sys.modules:
         from django.utils.datastructures import MultiValueDict
         # it should go before dict
         _TypeMap.insert(0, (MultiValueDict, multiValueDictResolver))
-        # django may not be installed
+        _TryDjango = False
     
-    with contextlib.suppress(ImportError):
-        from collections.abc import ItemsView, KeysView, ValuesView
-        _TypeMap.append((ItemsView, dictViewResolver))
-        _TypeMap.append((KeysView, dictViewResolver))
-        _TypeMap.append((ValuesView, dictViewResolver))
-        # not available on all Python versions
+    # If _TypeMap changed, rebuild the _ArrayTypes tuple
+    if _MapCount != len(_TypeMap):
+        _ArrayTypes = tuple(typ for typ, _resolver in _TypeMap)
+        _MapCount = len(_TypeMap)
 
 
-def getType(obj):
+def getResolver(obj):
     """
-    Public method to get the type information for an object.
+    Public method to get the resolver based on the type info of an object.
     
-    @param obj object to get type information for
+    @param obj object to get resolver for
     @type any
-    @return tuple containing the type name, type string and resolver
-    @rtype tuple of str, str, BaseResolver
+    @return resolver
+    @rtype BaseResolver
     """
-    typeObject = type(obj)
-    typeName = typeObject.__name__
     # Between PyQt and PySide the returned type is different (class vs. type)
-    typeStr = str(typeObject).split(' ', 1)[-1]
+    typeStr = str(type(obj)).split(' ', 1)[-1]
     typeStr = typeStr[1:-2]
     
     if (
         typeStr.startswith(ConfigQtNames) and
         typeStr.endswith(ConfigKnownQtTypes)
     ):
-        resolver = None
-    else:
-        if _TypeMap is None:
-            _initTypeMap()
-        
-        for typeData, resolver in _TypeMap:  # __IGNORE_WARNING_M507__
-            if isinstance(obj, typeData):
-                break
-        else:
-            resolver = defaultResolver
+        return qtResolver
     
-    return typeName, typeStr, resolver
+    for typeData, resolver in _TypeMap:  # __IGNORE_WARNING_M507__
+        if isinstance(obj, typeData):
+            return resolver
+    
+    return defaultResolver
 
 #
 # eflag: noqa = Y113
--- a/eric7/Debugger/Config.py	Wed Sep 01 19:42:43 2021 +0200
+++ b/eric7/Debugger/Config.py	Wed Sep 01 19:54:34 2021 +0200
@@ -13,10 +13,8 @@
 ConfigVarTypeDispStrings = {
     '__': QT_TRANSLATE_NOOP('Variable Types', 'Hidden Attributes'),
     'NoneType': QT_TRANSLATE_NOOP('Variable Types', 'None'),
-    'type': QT_TRANSLATE_NOOP('Variable Types', 'Type'),
     'bool': QT_TRANSLATE_NOOP('Variable Types', 'Boolean'),
     'int': QT_TRANSLATE_NOOP('Variable Types', 'Integer'),
-    'long': QT_TRANSLATE_NOOP('Variable Types', 'Long Integer'),
     'float': QT_TRANSLATE_NOOP('Variable Types', 'Float'),
     'complex': QT_TRANSLATE_NOOP('Variable Types', 'Complex'),
     'str': QT_TRANSLATE_NOOP('Variable Types', 'String'),
@@ -27,7 +25,7 @@
     'set': QT_TRANSLATE_NOOP('Variable Types', 'Set'),
     'frozenset': QT_TRANSLATE_NOOP('Variable Types', 'Frozen Set'),
     'file': QT_TRANSLATE_NOOP('Variable Types', 'File'),
-    'xrange': QT_TRANSLATE_NOOP('Variable Types', 'X Range'),
+    'range': QT_TRANSLATE_NOOP('Variable Types', 'Range'),
     'slice': QT_TRANSLATE_NOOP('Variable Types', 'Slice'),
     'buffer': QT_TRANSLATE_NOOP('Variable Types', 'Buffer'),
     'class': QT_TRANSLATE_NOOP('Variable Types', 'Class'),
@@ -46,4 +44,11 @@
     'bytes': QT_TRANSLATE_NOOP('Variable Types', 'Bytes'),
     "special_attributes": QT_TRANSLATE_NOOP(
         'Variable Types', "Special Attributes"),
+    'dict_items': QT_TRANSLATE_NOOP('Variable Types', 'Dict. Items View'),
+    'dict_keys': QT_TRANSLATE_NOOP('Variable Types', 'Dict. Keys View'),
+    'dict_values': QT_TRANSLATE_NOOP('Variable Types', 'Dict. Values View'),
+    'async_generator': QT_TRANSLATE_NOOP('Variable Types',
+        'Asynchronous Generator'),
+    'coroutine': QT_TRANSLATE_NOOP('Variable Types', 'Coroutine'),
+    'mappingproxy': QT_TRANSLATE_NOOP('Variable Types', 'Mapping Proxy'),
 }
--- a/eric7/Debugger/DebugUI.py	Wed Sep 01 19:42:43 2021 +0200
+++ b/eric7/Debugger/DebugUI.py	Wed Sep 01 19:54:34 2021 +0200
@@ -1434,7 +1434,9 @@
             elif scope == 0:
                 self.debugViewer.showVariables(variables, False)
             elif scope == -1:
-                vlist = [(self.tr('No locals available.'), '', '')]
+                vlist = [
+                    (self.tr('No locals available.'), '', '', False, -2, '')
+                ]
                 self.debugViewer.showVariables(vlist, False)
         
     def __clientVariable(self, scope, variables, debuggerId):
--- a/eric7/Debugger/VariablesViewer.py	Wed Sep 01 19:42:43 2021 +0200
+++ b/eric7/Debugger/VariablesViewer.py	Wed Sep 01 19:54:34 2021 +0200
@@ -21,7 +21,6 @@
 from EricWidgets.EricApplication import ericApp
 
 from .Config import ConfigVarTypeDispStrings
-from DebugClients.Python.DebugConfig import ConfigQtNames, ConfigKnownQtTypes
 
 import Preferences
 import Utilities
@@ -33,34 +32,14 @@
     """
     Class implementing the data structure for all variable items.
     """
-    Type2Indicators = {
-        # Python types
-        'list': '[]',
-        'tuple': '()',
-        'dict': '{:}',                          # __IGNORE_WARNING_M613__
-        'set': '{}',                            # __IGNORE_WARNING_M613__
-        'frozenset': '{}',                      # __IGNORE_WARNING_M613__
-        'numpy.ndarray': '[ndarray]',           # __IGNORE_WARNING_M613__
-    }
-    
     # Initialize regular expression for unprintable strings
     rx_nonprintable = re.compile(r"""(\\x\d\d)+""")
     
     noOfItemsStr = QCoreApplication.translate("VariablesViewer", "{0} items")
     unsized = QCoreApplication.translate("VariablesViewer", "unsized")
     
-    arrayTypes = {
-        'list', 'tuple', 'dict', 'set', 'frozenset', 'numpy.ndarray',
-        'django.MultiValueDict', 'array.array', 'collections.defaultdict',
-        "class 'dict_items'", "class 'dict_keys'", "class 'dict_values'",
-    }
-    
-    nonExpandableTypes = (
-        'method_descriptor', 'wrapper_descriptor', '', 'getset_descriptor',
-        'method-wrapper', 'member_descriptor',
-    )
-    
-    def __init__(self, parent, dvar, dtype, dvalue):
+    def __init__(self, parent, dvar, indicator, dtype, hasChildren, length,
+                 dvalue):
         """
         Constructor
         
@@ -68,8 +47,15 @@
         @type VariableItem
         @param dvar variable name
         @type str
+        @param indicator type indicator appended to the name
+        @type str
         @param dtype type string
         @type str
+        @param hasChildren indicator for children
+        @type bool
+        @param length length of the array or string (-1 if uninitialized
+            numpy.ndarray)
+        @type int
         @param dvalue value string
         @type str
         """
@@ -79,7 +65,7 @@
         self.childCount = 0
         self.currentCount = -1  # -1 indicates to (re)load children
         # Indicator that there are children
-        self.hasChildren = False
+        self.hasChildren = hasChildren
         self.populated = False
         # Indicator that item was at least once fully populated
         self.wasPopulated = False
@@ -97,15 +83,15 @@
         
         self.name = ''
         self.sort = ''
-        self.type = ''
-        self.indicator = ''
-        self.value = None
+        vtype = ConfigVarTypeDispStrings.get(dtype, dtype)
+        self.type = QCoreApplication.translate("VariablesViewer", vtype)
+        self.indicator = indicator
+        self.value = dvalue
         self.valueShort = None
         self.tooltip = ''
         
         self.__getName(dvar)
-        self.__getType(dtype)
-        self.__getValue(dtype, dvalue)
+        self.__getValue(dtype, dvalue, indicator, length)
     
     def __getName(self, dvar):
         """
@@ -126,45 +112,12 @@
         self.name = dvar
         try:
             # Convert numbers to strings with preceding zeros
-            sort = int(dvar)
-            sort = "{0:06}".format(sort)
+            asInt = int(dvar)
+            self.sort = "{0:06}".format(asInt)
         except ValueError:
-            sort = dvar.lower()
-        
-        self.sort = sort
+            self.sort = dvar.lower()
     
-    def __getType(self, dtype):
-        """
-        Private method to process the type of the variable.
-        
-        If type is known to have children, the corresponding flag is set.
-        
-        @param dtype type string
-        @type str
-        """
-        # Python class?
-        if dtype.startswith('class '):
-            dtype = dtype[7:-1]
-        # Qt related stuff?
-        elif (
-            (dtype.startswith(ConfigQtNames) and
-             dtype.endswith(ConfigKnownQtTypes)) or
-            dtype in ('instance', 'class')
-        ):
-            self.hasChildren = True
-        
-        # Special Qt types should not be expanded infinite
-        elif ".{0}".format(dtype) in ConfigKnownQtTypes:
-            self.type = dtype  # It's a Qt type, so skipping translation is ok
-            return
-        
-        vtype = ConfigVarTypeDispStrings.get(dtype, dtype)
-        # Unkown types should be expandable by default
-        if vtype is dtype and dtype not in self.nonExpandableTypes:
-            self.hasChildren = True
-        self.type = QCoreApplication.translate("VariablesViewer", vtype)
-    
-    def __getValue(self, dtype, dvalue):
+    def __getValue(self, dtype, dvalue, indicator, length):
         """
         Private method to process the variables value.
         
@@ -175,62 +128,33 @@
         @type str
         @param dvalue value of variable encoded as utf-8
         @type str
+        @param indicator type indicator appended to the name
+        @type str
+        @param length length of the array or string (-1 if uninitialized
+            numpy.ndarray)
+        @type int or str
         """
-        if dtype == 'collections.defaultdict':
-            dvalue, default_factory = dvalue.split('|')
-            self.indicator = '{{:<{0}>}}'.format(default_factory)
-        elif dtype == 'array.array':
-            dvalue, typecode = dvalue.split('|')
-            self.indicator = '[<{0}>]'.format(typecode)
-        else:
-            self.indicator = VariableItem.Type2Indicators.get(dtype, '')
-        
-        if dtype == 'numpy.ndarray':
-            if dvalue:
-                self.childCount = int(dvalue.split('x')[0])
-                dvalue = VariableItem.noOfItemsStr.format(dvalue)
-            else:
-                dvalue = VariableItem.unsized
-            self.hasChildren = True
-        
-        elif dtype in VariableItem.arrayTypes:
-            self.childCount = int(dvalue)
-            dvalue = VariableItem.noOfItemsStr.format(dvalue)
-            self.hasChildren = True
-        
-        elif dtype == "Shiboken.EnumType":
-            self.hasChildren = True
+        length_code = length
+        if isinstance(length, str):
+            length = int(length.split('x')[0])
         
-        elif dtype == 'str':
-            if VariableItem.rx_nonprintable.search(dvalue) is None:
-                with contextlib.suppress(Exception):
-                    dvalue = ast.literal_eval(dvalue)
-            dvalue = str(dvalue)
+        if indicator and length > -2:
+            self.childCount = max(0, length)  # Update count if array
+            if dtype == 'numpy.ndarray' and length == -1:
+                self.value = VariableItem.unsized
+            else:
+                self.value = VariableItem.noOfItemsStr.format(length_code)
         
-        elif (
-            dvalue.startswith(("{", "(", "[")) and
-            dvalue.endswith(("}", ")", "]"))
-        ):
-            # it is most probably a dict, tuple or list derived class
+        if dtype != 'str':
+            self.valueShort = self.value
+            self.tooltip = str(self.value)[:256]
+            return
+        
+        if VariableItem.rx_nonprintable.search(dvalue) is None:
             with contextlib.suppress(Exception):
-                value = ast.literal_eval(dvalue)
-                valueTypeStr = str(type(value))[8:-2]
-                if valueTypeStr in VariableItem.arrayTypes:
-                    self.childCount = len(value)
-                    self.hasChildren = True
+                dvalue = ast.literal_eval(dvalue)
         
-        elif (
-            (dvalue.endswith("})") and "({" in dvalue) or
-            (dvalue.endswith("])") and "([" in dvalue)
-        ):
-            # that is probably a set derived class
-            with contextlib.suppress(Exception):
-                value = ast.literal_eval(dvalue.split("(", 1)[1][:-1])
-                valueTypeStr = str(type(value))[8:-2]
-                if valueTypeStr in VariableItem.arrayTypes:
-                    self.childCount = len(value)
-                    self.hasChildren = True
-        
+        dvalue = str(dvalue)
         self.value = dvalue
         
         if len(dvalue) > 2048:     # 2 kB
@@ -296,8 +220,8 @@
         self.closedItems = []
         
         visibility = self.tr("Globals") if globalScope else self.tr("Locals")
-        self.rootNode = VariableItem(None, visibility, self.tr("Type"),
-                                     self.tr("Value"))
+        self.rootNode = VariableItem(None, visibility, '', self.tr("Type"),
+                                     True, 0, self.tr("Value"))
         
         self.__globalScope = globalScope
     
@@ -403,8 +327,6 @@
             idx = itemStartIndex
             parent.currentCount = idx + len(vlist)
         
-        # Sort items for Python versions where dict doesn't retain order
-        vlist.sort(key=lambda x: x[0])
         # Now update the table
         endIndex = idx + len(vlist)
         newChild = None
@@ -668,7 +590,7 @@
                         3: node.sort
                     }.get(column)
             except AttributeError:
-                return ['None', '', '', ''][column]
+                return ('None', '', '', '')[column]
         
         elif role == Qt.ItemDataRole.BackgroundRole:
             if node in node.parent.changedItems:
@@ -722,7 +644,7 @@
         """
         Public method get the header names.
         
-        @param section the header section (row/coulumn)
+        @param section the header section (row/column)
         @type int
         @param orientation the header's orientation
         @type QtCore.Qt.Orientation

eric ide

mercurial