from _pydev_bundle import pydev_log from _pydevd_bundle import pydevd_extension_utils from _pydevd_bundle import pydevd_resolver import sys from _pydevd_bundle.pydevd_constants import dict_iter_items, dict_keys, IS_PY3K, \ BUILTINS_MODULE_NAME, MAXIMUM_VARIABLE_REPRESENTATION_SIZE, RETURN_VALUES_DICT, LOAD_VALUES_ASYNC, \ DEFAULT_VALUE from _pydev_bundle.pydev_imports import quote from _pydevd_bundle.pydevd_extension_api import TypeResolveProvider, StrPresentationProvider from _pydevd_bundle.pydevd_utils import isinstance_checked, hasattr_checked, DAPGrouper from _pydevd_bundle.pydevd_resolver import get_var_scope try: import types frame_type = types.FrameType except: frame_type = None def make_valid_xml_value(s): # Same thing as xml.sax.saxutils.escape but also escaping double quotes. return s.replace("&", "&").replace('<', '<').replace('>', '>').replace('"', '"') class ExceptionOnEvaluate: def __init__(self, result, etype, tb): self.result = result self.etype = etype self.tb = tb _IS_JYTHON = sys.platform.startswith("java") def _create_default_type_map(): default_type_map = [ # None means that it should not be treated as a compound variable # isintance does not accept a tuple on some versions of python, so, we must declare it expanded (type(None), None,), (int, None), (float, None), (complex, None), (str, None), (tuple, pydevd_resolver.tupleResolver), (list, pydevd_resolver.tupleResolver), (dict, pydevd_resolver.dictResolver), ] try: from collections import OrderedDict default_type_map.insert(0, (OrderedDict, pydevd_resolver.orderedDictResolver)) # we should put it before dict except: pass try: default_type_map.append((long, None)) # @UndefinedVariable except: pass # not available on all python versions try: default_type_map.append((unicode, None)) # @UndefinedVariable except: pass # not available on all python versions default_type_map.append((DAPGrouper, pydevd_resolver.dapGrouperResolver)) try: default_type_map.append((set, pydevd_resolver.setResolver)) except: pass # not available on all python versions try: default_type_map.append((frozenset, pydevd_resolver.setResolver)) except: pass # not available on all python versions try: from django.utils.datastructures import MultiValueDict default_type_map.insert(0, (MultiValueDict, pydevd_resolver.multiValueDictResolver)) # we should put it before dict except: pass # django may not be installed try: from django.forms import BaseForm default_type_map.insert(0, (BaseForm, pydevd_resolver.djangoFormResolver)) # we should put it before instance resolver except: pass # django may not be installed try: from collections import deque default_type_map.append((deque, pydevd_resolver.dequeResolver)) except: pass if frame_type is not None: default_type_map.append((frame_type, pydevd_resolver.frameResolver)) if _IS_JYTHON: from org.python import core # @UnresolvedImport default_type_map.append((core.PyNone, None)) default_type_map.append((core.PyInteger, None)) default_type_map.append((core.PyLong, None)) default_type_map.append((core.PyFloat, None)) default_type_map.append((core.PyComplex, None)) default_type_map.append((core.PyString, None)) default_type_map.append((core.PyTuple, pydevd_resolver.tupleResolver)) default_type_map.append((core.PyList, pydevd_resolver.tupleResolver)) default_type_map.append((core.PyDictionary, pydevd_resolver.dictResolver)) default_type_map.append((core.PyStringMap, pydevd_resolver.dictResolver)) if hasattr(core, 'PyJavaInstance'): # Jython 2.5b3 removed it. default_type_map.append((core.PyJavaInstance, pydevd_resolver.instanceResolver)) return default_type_map class TypeResolveHandler(object): NO_PROVIDER = [] # Sentinel value (any mutable object to be used as a constant would be valid). def __init__(self): # Note: don't initialize with the types we already know about so that the extensions can override # the default resolvers that are already available if they want. self._type_to_resolver_cache = {} self._type_to_str_provider_cache = {} self._initialized = False def _initialize(self): self._default_type_map = _create_default_type_map() self._resolve_providers = pydevd_extension_utils.extensions_of_type(TypeResolveProvider) self._str_providers = pydevd_extension_utils.extensions_of_type(StrPresentationProvider) self._initialized = True def get_type(self, o): try: try: # Faster than type(o) as we don't need the function call. type_object = o.__class__ # could fail here type_name = type_object.__name__ return self._get_type(o, type_object, type_name) # could fail here except: # Not all objects have __class__ (i.e.: there are bad bindings around). type_object = type(o) type_name = type_object.__name__ try: return self._get_type(o, type_object, type_name) except: if isinstance(type_object, type): # If it's still something manageable, use the default resolver, otherwise # fallback to saying that it wasn't possible to get any info on it. return type_object, str(type_name), pydevd_resolver.defaultResolver return 'Unable to get Type', 'Unable to get Type', None except: # This happens for org.python.core.InitModule return 'Unable to get Type', 'Unable to get Type', None def _get_type(self, o, type_object, type_name): # Note: we could have an exception here if the type_object is not hashable... resolver = self._type_to_resolver_cache.get(type_object) if resolver is not None: return type_object, type_name, resolver if not self._initialized: self._initialize() try: for resolver in self._resolve_providers: if resolver.can_provide(type_object, type_name): # Cache it self._type_to_resolver_cache[type_object] = resolver return type_object, type_name, resolver for t in self._default_type_map: if isinstance_checked(o, t[0]): # Cache it resolver = t[1] self._type_to_resolver_cache[type_object] = resolver return (type_object, type_name, resolver) except: pydev_log.exception() # No match return default (and cache it). resolver = pydevd_resolver.defaultResolver self._type_to_resolver_cache[type_object] = resolver return type_object, type_name, resolver if _IS_JYTHON: _base_get_type = _get_type def _get_type(self, o, type_object, type_name): if type_name == 'org.python.core.PyJavaInstance': return type_object, type_name, pydevd_resolver.instanceResolver if type_name == 'org.python.core.PyArray': return type_object, type_name, pydevd_resolver.jyArrayResolver return self._base_get_type(o, type_object, type_name) def str_from_providers(self, o, type_object, type_name): provider = self._type_to_str_provider_cache.get(type_object) if provider is self.NO_PROVIDER: return None if provider is not None: return provider.get_str(o) if not self._initialized: self._initialize() for provider in self._str_providers: if provider.can_provide(type_object, type_name): self._type_to_str_provider_cache[type_object] = provider return provider.get_str(o) self._type_to_str_provider_cache[type_object] = self.NO_PROVIDER return None _TYPE_RESOLVE_HANDLER = TypeResolveHandler() """ def get_type(o): Receives object and returns a triple (type_object, type_string, resolver). resolver != None means that variable is a container, and should be displayed as a hierarchy. Use the resolver to get its attributes. All container objects (i.e.: dict, list, tuple, object, etc) should have a resolver. """ get_type = _TYPE_RESOLVE_HANDLER.get_type _str_from_providers = _TYPE_RESOLVE_HANDLER.str_from_providers def is_builtin(x): return getattr(x, '__module__', None) == BUILTINS_MODULE_NAME def should_evaluate_full_value(val): return not LOAD_VALUES_ASYNC or (is_builtin(type(val)) and not isinstance_checked(val, (list, tuple, dict))) def return_values_from_dict_to_xml(return_dict): res = "" for name, val in dict_iter_items(return_dict): res += var_to_xml(val, name, additional_in_xml=' isRetVal="True"') return res def frame_vars_to_xml(frame_f_locals, hidden_ns=None): """ dumps frame variables to XML """ xml = "" keys = dict_keys(frame_f_locals) if hasattr(keys, 'sort'): keys.sort() # Python 3.0 does not have it else: keys = sorted(keys) # Jython 2.1 does not have it return_values_xml = '' for k in keys: try: v = frame_f_locals[k] eval_full_val = should_evaluate_full_value(v) if k == '_pydev_stop_at_break': continue if k == RETURN_VALUES_DICT: for name, val in dict_iter_items(v): return_values_xml += var_to_xml(val, name, additional_in_xml=' isRetVal="True"') else: if hidden_ns is not None and k in hidden_ns: xml += var_to_xml(v, str(k), additional_in_xml=' isIPythonHidden="True"', evaluate_full_value=eval_full_val) else: xml += var_to_xml(v, str(k), evaluate_full_value=eval_full_val) except Exception: pydev_log.exception("Unexpected error, recovered safely.") # Show return values as the first entry. return return_values_xml + xml def get_variable_details(val, evaluate_full_value=True, to_string=None): try: # This should be faster than isinstance (but we have to protect against not having a '__class__' attribute). is_exception_on_eval = val.__class__ == ExceptionOnEvaluate except: is_exception_on_eval = False if is_exception_on_eval: v = val.result else: v = val _type, type_name, resolver = get_type(v) type_qualifier = getattr(_type, "__module__", "") if not evaluate_full_value: value = DEFAULT_VALUE else: try: str_from_provider = _str_from_providers(v, _type, type_name) if str_from_provider is not None: value = str_from_provider elif to_string is not None: value = to_string(v) elif hasattr_checked(v, '__class__'): if v.__class__ == frame_type: value = pydevd_resolver.frameResolver.get_frame_name(v) elif v.__class__ in (list, tuple): if len(v) > 300: value = '%s: %s' % (str(v.__class__), '' % (len(v),)) else: value = '%s: %s' % (str(v.__class__), v) else: try: cName = str(v.__class__) if cName.find('.') != -1: cName = cName.split('.')[-1] elif cName.find("'") != -1: # does not have '.' (could be something like ) cName = cName[cName.index("'") + 1:] if cName.endswith("'>"): cName = cName[:-2] except: cName = str(v.__class__) value = '%s: %s' % (cName, v) else: value = str(v) except: try: value = repr(v) except: value = 'Unable to get repr for %s' % v.__class__ # fix to work with unicode values try: if not IS_PY3K: if value.__class__ == unicode: # @UndefinedVariable value = value.encode('utf-8', 'replace') else: if value.__class__ == bytes: value = value.decode('utf-8', 'replace') except TypeError: pass return type_name, type_qualifier, is_exception_on_eval, resolver, value def var_to_xml(val, name, trim_if_too_big=True, additional_in_xml='', evaluate_full_value=True): """ single variable or dictionary to xml representation """ type_name, type_qualifier, is_exception_on_eval, resolver, value = get_variable_details( val, evaluate_full_value) scope = get_var_scope(name, val, '', True) try: name = quote(name, '/>_= ') # TODO: Fix PY-5834 without using quote except: pass xml = ' MAXIMUM_VARIABLE_REPRESENTATION_SIZE and trim_if_too_big: value = value[0:MAXIMUM_VARIABLE_REPRESENTATION_SIZE] value += '...' xml_value = ' value="%s"' % (make_valid_xml_value(quote(value, '/>_= '))) else: xml_value = '' if is_exception_on_eval: xml_container = ' isErrorOnEval="True"' else: if resolver is not None: xml_container = ' isContainer="True"' else: xml_container = '' if scope: return ''.join((xml, xml_qualifier, xml_value, xml_container, additional_in_xml, ' scope="', scope, '"', ' />\n')) else: return ''.join((xml, xml_qualifier, xml_value, xml_container, additional_in_xml, ' />\n'))