Variable view in Python Console.

This commit is contained in:
Dmitry Trofimov
2013-09-03 14:48:54 +02:00
parent f67487028d
commit fd689cb7dc
19 changed files with 833 additions and 246 deletions
+12 -1
View File
@@ -17,6 +17,8 @@ import traceback
import fix_getpass
fix_getpass.fixGetpass()
import pydevd_xml
try:
if USE_LIB_COPY:
import _pydev_Queue as _queue
@@ -162,7 +164,13 @@ class InterpreterInterface(BaseInterpreterInterface):
traceback.print_exc()
return []
def getFrame(self):
xml = "<xml>"
xml += pydevd_xml.frameVarsToXML(self.namespace)
xml += "</xml>"
return xml
def close(self):
sys.exit(0)
@@ -265,6 +273,7 @@ def start_server(host, port, interpreter):
server.register_function(interpreter.execLine)
server.register_function(interpreter.getCompletions)
server.register_function(interpreter.getFrame)
server.register_function(interpreter.getDescription)
server.register_function(interpreter.close)
server.register_function(interpreter.interrupt)
@@ -323,6 +332,8 @@ def get_completions(text, token, globals, locals):
return interpreterInterface.getCompletions(text, token)
def get_frame(globals, locals):
return interpreterInterface.getFrame()
def exec_expression(expression, globals, locals):
interpreterInterface = get_interpreter()
+2 -2
View File
@@ -604,7 +604,7 @@ class NetCommandFactory:
#print "line is ", myLine
#the variables are all gotten 'on-demand'
#variables = pydevd_vars.frameVarsToXML(curFrame)
#variables = pydevd_vars.frameVarsToXML(curFrame.f_locals)
variables = ''
cmdTextList.append('<frame id="%s" name="%s" ' % (myId , pydevd_vars.makeValidXmlValue(myName)))
@@ -839,7 +839,7 @@ class InternalGetFrame(InternalThreadCommand):
frame = pydevd_vars.findFrame(self.thread_id, self.frame_id)
if frame is not None:
xml = "<xml>"
xml += pydevd_vars.frameVarsToXML(frame)
xml += pydevd_vars.frameVarsToXML(frame.f_locals)
del frame
xml += "</xml>"
cmd = dbg.cmdFactory.makeGetFrameMessage(self.sequence, xml)
+4
View File
@@ -6,6 +6,7 @@ except:
from urllib.parse import quote
import pydevd_constants
import pydev_log
def to_number(x):
if is_string(x):
@@ -92,4 +93,7 @@ def quote_smart(s, safe='/'):
s = s.encode('utf-8')
return quote(s, safe)
+1 -201
View File
@@ -8,7 +8,7 @@ from types import * #@UnusedWildImport
from code import compile_command
from code import InteractiveInterpreter
import pydevconsole
import pydev_log
from pydevd_xml import *
try:
from StringIO import StringIO
@@ -16,11 +16,6 @@ except ImportError:
from io import StringIO
import sys #@Reimport
try:
from urllib import quote
except:
from urllib.parse import quote #@UnresolvedImport
if USE_LIB_COPY:
import _pydev_threading as threading
else:
@@ -50,177 +45,6 @@ class VariableError(RuntimeError): pass
class FrameNotFoundError(RuntimeError): pass
#------------------------------------------------------------------------------------------------------ resolvers in map
if not sys.platform.startswith("java"):
typeMap = [
#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:
typeMap.append((long, None))
except:
pass #not available on all python versions
try:
typeMap.append((unicode, None))
except:
pass #not available on all python versions
try:
typeMap.append((set, pydevd_resolver.setResolver))
except:
pass #not available on all python versions
try:
typeMap.append((frozenset, pydevd_resolver.setResolver))
except:
pass #not available on all python versions
else: #platform is java
from org.python import core #@UnresolvedImport
typeMap = [
(core.PyNone, None),
(core.PyInteger, None),
(core.PyLong, None),
(core.PyFloat, None),
(core.PyComplex, None),
(core.PyString, None),
(core.PyTuple, pydevd_resolver.tupleResolver),
(core.PyList, pydevd_resolver.tupleResolver),
(core.PyDictionary, pydevd_resolver.dictResolver),
(core.PyStringMap, pydevd_resolver.dictResolver),
]
if hasattr(core, 'PyJavaInstance'):
#Jython 2.5b3 removed it.
typeMap.append((core.PyJavaInstance, pydevd_resolver.instanceResolver))
def getType(o):
""" returns a triple (typeObject, typeString, 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 should have a resolver.
"""
try:
type_object = type(o)
type_name = type_object.__name__
except:
#This happens for org.python.core.InitModule
return 'Unable to get Type', 'Unable to get Type', None
try:
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
for t in typeMap:
if isinstance(o, t[0]):
return type_object, type_name, t[1]
except:
traceback.print_exc()
#no match return default
return type_object, type_name, pydevd_resolver.defaultResolver
try:
from xml.sax.saxutils import escape
def makeValidXmlValue(s):
return escape(s, {'"': '&quot;'})
except:
#Simple replacement if it's not there.
def makeValidXmlValue(s):
return s.replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
def varToXML(val, name, doTrim=True):
""" single variable or dictionary to xml representation """
is_exception_on_eval = isinstance(val, ExceptionOnEvaluate)
if is_exception_on_eval:
v = val.result
else:
v = val
type, typeName, resolver = getType(v)
try:
if hasattr(v, '__class__'):
try:
cName = str(v.__class__)
if cName.find('.') != -1:
cName = cName.split('.')[-1]
elif cName.find("'") != -1: #does not have '.' (could be something like <type 'int'>)
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__
xml = '<var name="%s" type="%s"' % (makeValidXmlValue(quote(name, '/>_= ')), makeValidXmlValue(typeName))
if value:
#cannot be too big... communication may not handle it.
if len(value) > MAXIMUM_VARIABLE_REPRESENTATION_SIZE and doTrim:
value = value[0:MAXIMUM_VARIABLE_REPRESENTATION_SIZE]
value += '...'
#fix to work with unicode values
try:
if not IS_PY3K:
if isinstance(value, unicode):
value = value.encode('utf-8')
else:
if isinstance(value, bytes):
value = value.encode('utf-8')
except TypeError: #in java, unicode is a function
pass
xmlValue = ' value="%s"' % (makeValidXmlValue(quote(value, '/>_= ')))
else:
xmlValue = ''
if is_exception_on_eval:
xmlCont = ' isErrorOnEval="True"'
else:
if resolver is not None:
xmlCont = ' isContainer="True"'
else:
xmlCont = ''
return ''.join((xml, xmlValue, xmlCont, ' />\n'))
if USE_PSYCO_OPTIMIZATION:
try:
import psyco
@@ -231,27 +55,7 @@ if USE_PSYCO_OPTIMIZATION:
sys.exc_clear() #don't keep the traceback -- clients don't want to see it
def frameVarsToXML(frame):
""" dumps frame variables to XML
<var name="var_name" scope="local" type="type" value="value"/>
"""
xml = ""
keys = frame.f_locals.keys()
if hasattr(keys, 'sort'):
keys.sort() #Python 3.0 does not have it
else:
keys = sorted(keys) #Jython 2.1 does not have it
for k in keys:
try:
v = frame.f_locals[k]
xml += varToXML(v, str(k))
except Exception:
traceback.print_exc()
pydev_log.error("Unexpected error, recovered safely.\n")
return xml
def iterFrames(initialFrame):
"""NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)"""
@@ -378,10 +182,6 @@ def resolveCompoundVariable(thread_id, frame_id, scope, attrs):
except:
traceback.print_exc()
class ExceptionOnEvaluate:
def __init__(self, result):
self.result = result
def evaluateExpression(thread_id, frame_id, expression, doExec):
"""returns the result of the evaluated expression
@param doExec: determines if we should do an exec or an eval
+205
View File
@@ -0,0 +1,205 @@
import pydev_log
import traceback
import pydevd_resolver
from pydevd_constants import * #@UnusedWildImport
from types import * #@UnusedWildImport
try:
from urllib import quote
except:
from urllib.parse import quote #@UnresolvedImport
try:
from xml.sax.saxutils import escape
def makeValidXmlValue(s):
return escape(s, {'"': '&quot;'})
except:
#Simple replacement if it's not there.
def makeValidXmlValue(s):
return s.replace('<', '&lt;').replace('>', '&gt;').replace('"', '&quot;')
class ExceptionOnEvaluate:
def __init__(self, result):
self.result = result
#------------------------------------------------------------------------------------------------------ resolvers in map
if not sys.platform.startswith("java"):
typeMap = [
#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:
typeMap.append((long, None))
except:
pass #not available on all python versions
try:
typeMap.append((unicode, None))
except:
pass #not available on all python versions
try:
typeMap.append((set, pydevd_resolver.setResolver))
except:
pass #not available on all python versions
try:
typeMap.append((frozenset, pydevd_resolver.setResolver))
except:
pass #not available on all python versions
else: #platform is java
from org.python import core #@UnresolvedImport
typeMap = [
(core.PyNone, None),
(core.PyInteger, None),
(core.PyLong, None),
(core.PyFloat, None),
(core.PyComplex, None),
(core.PyString, None),
(core.PyTuple, pydevd_resolver.tupleResolver),
(core.PyList, pydevd_resolver.tupleResolver),
(core.PyDictionary, pydevd_resolver.dictResolver),
(core.PyStringMap, pydevd_resolver.dictResolver),
]
if hasattr(core, 'PyJavaInstance'):
#Jython 2.5b3 removed it.
typeMap.append((core.PyJavaInstance, pydevd_resolver.instanceResolver))
def getType(o):
""" returns a triple (typeObject, typeString, 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 should have a resolver.
"""
try:
type_object = type(o)
type_name = type_object.__name__
except:
#This happens for org.python.core.InitModule
return 'Unable to get Type', 'Unable to get Type', None
try:
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
for t in typeMap:
if isinstance(o, t[0]):
return type_object, type_name, t[1]
except:
traceback.print_exc()
#no match return default
return type_object, type_name, pydevd_resolver.defaultResolver
def frameVarsToXML(frame_f_locals):
""" dumps frame variables to XML
<var name="var_name" scope="local" type="type" value="value"/>
"""
xml = ""
keys = frame_f_locals.keys()
if hasattr(keys, 'sort'):
keys.sort() #Python 3.0 does not have it
else:
keys = sorted(keys) #Jython 2.1 does not have it
for k in keys:
try:
v = frame_f_locals[k]
xml += varToXML(v, str(k))
except Exception:
traceback.print_exc()
pydev_log.error("Unexpected error, recovered safely.\n")
return xml
def varToXML(val, name, doTrim=True):
""" single variable or dictionary to xml representation """
is_exception_on_eval = isinstance(val, ExceptionOnEvaluate)
if is_exception_on_eval:
v = val.result
else:
v = val
type, typeName, resolver = getType(v)
try:
if hasattr(v, '__class__'):
try:
cName = str(v.__class__)
if cName.find('.') != -1:
cName = cName.split('.')[-1]
elif cName.find("'") != -1: #does not have '.' (could be something like <type 'int'>)
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__
xml = '<var name="%s" type="%s"' % (makeValidXmlValue(quote(name, '/>_= ')), makeValidXmlValue(typeName))
if value:
#cannot be too big... communication may not handle it.
if len(value) > MAXIMUM_VARIABLE_REPRESENTATION_SIZE and doTrim:
value = value[0:MAXIMUM_VARIABLE_REPRESENTATION_SIZE]
value += '...'
#fix to work with unicode values
try:
if not IS_PY3K:
if isinstance(value, unicode):
value = value.encode('utf-8')
else:
if isinstance(value, bytes):
value = value.encode('utf-8')
except TypeError: #in java, unicode is a function
pass
xmlValue = ' value="%s"' % (makeValidXmlValue(quote(value, '/>_= ')))
else:
xmlValue = ''
if is_exception_on_eval:
xmlCont = ' isErrorOnEval="True"'
else:
if resolver is not None:
xmlCont = ' isContainer="True"'
else:
xmlCont = ''
return ''.join((xml, xmlValue, xmlCont, ' />\n'))