DebugClients/Python3/DebugVariables.py

Wed, 14 Sep 2016 20:08:16 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Wed, 14 Sep 2016 20:08:16 +0200
changeset 5169
74e000797a93
child 5171
f1e9eebd5469
permissions
-rw-r--r--

Started to improve the variable dumping of the debugger backend.

# -*- coding: utf-8 -*-

# Copyright (c) 2016 Detlev Offenbach <detlev@die-offenbachs.de>
#

"""
Module implementing classes and functions to dump variable contents.
"""

#
# This code was inspired by pydevd.
#

MaxItemsToHandle = 300
TooLargeMessage = ("Too large to show contents. Max items to show: " + 
                   str(MaxItemsToHandle))
TooLargeAttribute = "Too large to be handled."

############################################################
## Classes implementing resolvers for various compund types
############################################################

class BaseResolver(object):
    """
    Base class of the resolver class tree.
    """
    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 any
        @param attribute name of the attribute to extract
        @type str
        @return value of the attribute
        @rtype any
        """
        raise NotImplementedError
    
    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
        """
        raise NotImplementedError


class DefaultResolver(BaseResolver):
    """
    Class used to resolve the default way.
    """
    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 any
        @param attribute name of the attribute to extract
        @type str
        @return value of the attribute
        @rtype any
        """
        return getattr(var, attribute)
    
    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
        """
        names = dir(var)
        if not names and hasattr(var, "__members__"):
            names = var.__members__
        
        d = {}
        for name in names:
            try:
                attribute = getattr(var, name)
                d[name] = attribute
            except Exception:
                pass    # if we can't get it, simply ignore it
        
        return d


class DictResolver(BaseResolver):
    """
    Class used to resolve from a dictionary.
    """
    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 "(" not in attribute:
            try:
##                if attribute[0] == "'" and attribute[-1] == "'":
##                    attribute = attribute[1:-1]
                return var[attribute]
            except Exception:
                return getattr(var, attribute)
        
        expectedID = int(attribute.split("(")[-1][:-1])
        for key, value in var.items():
            if id(key) == expectedID:
                return value
        
        return None
    
    def __keyToStr(self, key):
        if isinstance(key, str):
            return repr(key)
        else:
            return key
    
    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, value in var.items():
            count += 1
            key = "{0} ({1})".format(self.__keyToStr(key), id(key))
            d[key] = value
            if count > MaxItemsToHandle:
                d[TooLargeAttribute] = TooLargeMessage
                break
        
        d["__len__"] = len(var)
        
        # in case it has additional fields
        additionals = defaultResolver.getDictionary(var)
        d.update(additionals)
        
        return d


class ListResolver(BaseResolver):
    """
    Class used to resolve from a tuple or list.
    """
    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 name of the attribute to extract
        @type str
        @return value of the attribute
        @rtype any
        """
        if attribute in ('__len__', TooLargeAttribute):
            return None

        try:
            return var[int(attribute)]
        except Exception:
            return getattr(var, attribute)
    
    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
        """
        length = len(var)
        d = {}
        formatStr = "{0:0" + str(len(str(length))) + "d}"
        count = 0
        for value in var:
            d[formatStr.format(count)] = value
            count += 1
            if count > MaxItemsToHandle:
                d[TooLargeAttribute] = TooLargeMessage
                break
        
        d["__len__"] = length
        
        # in case it has additional fields
        additionals = defaultResolver.getDictionary(var)
        d.update(additionals)
        
        return d


defaultResolver = DefaultResolver()
dictResolver = DictResolver()
listResolver = ListResolver()

# TODO: add resolver for set and frozenset
# TODO: add resolver for numpy arrays
# TODO: add resolver for Django MultiValueDict
# TODO: add resolver for collections.deque

############################################################
## Methods to determine the type of a variable and the
## resolver class to use
############################################################

_TypeMap = None

def _initTypeMap():
    """
    Protected function to initialize the type map
    """
    global _TypeMap
    
    _TypeMap = [
        (type(None), None,),
        (int, None),
        (float, None),
        (complex, None),
        (str, None),
        (tuple, listResolver),
        (list, listResolver),
        (dict, dictResolver),
    ]
    
    try:
        _TypeMap.append((long, None))           # __IGNORE_WARNING__
    except Exception:
        pass    # not available on all python versions

    try:
        _TypeMap.append((unicode, None))        # __IGNORE_WARNING__
    except Exception:
        pass    # not available on all python versions


def getType(obj):
    """
    Public method to get the type information for an object.
    
    @param obj object to get type information for
    @type any
    @return tuple containing the type, type name, type string and resolver
    @rtype tuple of type, str, str, BaseResolver
    """
    typeObject = type(obj)
    typeName = typeObject.__name__
    typeStr = str(typeObject)[8:-2]
    
    if typeStr.startswith(("PyQt5.", "PyQt4.")):
        resolver = None
    else:
        if _TypeMap is None:
            _initTypeMap()
        
        for typeData in _TypeMap:
            if isinstance(obj, typeData[0]):
                resolver = typeData[1]
                break
        else:
            resolver = defaultResolver
    
    return typeObject, typeName, typeStr, resolver

eric ide

mercurial