diff options
Diffstat (limited to 'python/helpers/pydev/pydevd_vars.py')
-rw-r--r-- | python/helpers/pydev/pydevd_vars.py | 174 |
1 files changed, 125 insertions, 49 deletions
diff --git a/python/helpers/pydev/pydevd_vars.py b/python/helpers/pydev/pydevd_vars.py index de8c2415fcae..0cc45f73710f 100644 --- a/python/helpers/pydev/pydevd_vars.py +++ b/python/helpers/pydev/pydevd_vars.py @@ -3,7 +3,6 @@ """ import pickle from django_frame import DjangoTemplateFrame -from pydevd_constants import * #@UnusedWildImport from types import * #@UnusedWildImport from pydevd_custom_frames import getCustomFrame @@ -19,16 +18,15 @@ if USE_LIB_COPY: import _pydev_threading as threading else: import threading -import pydevd_resolver import traceback import pydevd_save_locals -from pydev_imports import Exec, quote, execfile +from pydev_imports import Exec, execfile try: import types frame_type = types.FrameType except: - frame_type = None + frame_type = type(sys._getframe()) #-------------------------------------------------------------------------- defining true and false for earlier versions @@ -37,25 +35,14 @@ try: __setFalse = False except: import __builtin__ - setattr(__builtin__, 'True', 1) setattr(__builtin__, 'False', 0) #------------------------------------------------------------------------------------------------------ class for errors -class VariableError(RuntimeError): pass - -class FrameNotFoundError(RuntimeError): pass - - -if USE_PSYCO_OPTIMIZATION: - try: - import psyco +class VariableError(RuntimeError):pass - varToXML = psyco.proxy(varToXML) - except ImportError: - if hasattr(sys, 'exc_clear'): #jython does not have it - sys.exc_clear() #don't keep the traceback -- clients don't want to see it +class FrameNotFoundError(RuntimeError):pass def iterFrames(initialFrame): '''NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)''' @@ -166,50 +153,127 @@ def findFrame(thread_id, frame_id): traceback.print_exc() return None -def resolveCompoundVariable(thread_id, frame_id, scope, attrs): - """ returns the value of the compound variable as a dictionary""" +def getVariable(thread_id, frame_id, scope, attrs): + """ + returns the value of a variable + + :scope: can be BY_ID, EXPRESSION, GLOBAL, LOCAL, FRAME + + BY_ID means we'll traverse the list of all objects alive to get the object. + + :attrs: after reaching the proper scope, we have to get the attributes until we find + the proper location (i.e.: obj\tattr1\tattr2) + + :note: when BY_ID is used, the frame_id is considered the id of the object to find and + not the frame (as we don't care about the frame in this case). + """ + if scope == 'BY_ID': + if thread_id != GetThreadId(threading.currentThread()) : + raise VariableError("getVariable: must execute on same thread") + + try: + import gc + objects = gc.get_objects() + except: + pass #Not all python variants have it. + else: + frame_id = int(frame_id) + for var in objects: + if id(var) == frame_id: + if attrs is not None: + attrList = attrs.split('\t') + for k in attrList: + _type, _typeName, resolver = getType(var) + var = resolver.resolve(var, k) + + return var + + #If it didn't return previously, we coudn't find it by id (i.e.: alrceady garbage collected). + sys.stderr.write('Unable to find object with id: %s\n' % (frame_id,)) + return None + frame = findFrame(thread_id, frame_id) if frame is None: return {} - attrList = attrs.split('\t') - - if scope == "GLOBAL": - var = frame.f_globals - del attrList[0] # globals are special, and they get a single dummy unused attribute + if attrs is not None: + attrList = attrs.split('\t') else: - var = frame.f_locals - type, _typeName, resolver = getType(var) - try: - resolver.resolve(var, attrList[0]) - except: + attrList = [] + + if scope == 'EXPRESSION': + for count in xrange(len(attrList)): + if count == 0: + # An Expression can be in any scope (globals/locals), therefore it needs to evaluated as an expression + var = evaluateExpression(thread_id, frame_id, attrList[count], False) + else: + _type, _typeName, resolver = getType(var) + var = resolver.resolve(var, attrList[count]) + else: + if scope == "GLOBAL": var = frame.f_globals + del attrList[0] # globals are special, and they get a single dummy unused attribute + else: + var = frame.f_locals + + for k in attrList: + _type, _typeName, resolver = getType(var) + var = resolver.resolve(var, k) + + return var - for k in attrList: - type, _typeName, resolver = getType(var) - var = resolver.resolve(var, k) + +def resolveCompoundVariable(thread_id, frame_id, scope, attrs): + """ returns the value of the compound variable as a dictionary""" + + var = getVariable(thread_id, frame_id, scope, attrs) try: - type, _typeName, resolver = getType(var) + _type, _typeName, resolver = getType(var) return resolver.getDictionary(var) except: + sys.stderr.write('Error evaluating: thread_id: %s\nframe_id: %s\nscope: %s\nattrs: %s\n' % ( + thread_id, frame_id, scope, attrs,)) traceback.print_exc() - - + + def resolveVar(var, attrs): attrList = attrs.split('\t') - + for k in attrList: type, _typeName, resolver = getType(var) - + var = resolver.resolve(var, k) - + try: type, _typeName, resolver = getType(var) return resolver.getDictionary(var) except: traceback.print_exc() - + + +def customOperation(thread_id, frame_id, scope, attrs, style, code_or_file, operation_fn_name): + """ + We'll execute the code_or_file and then search in the namespace the operation_fn_name to execute with the given var. + + code_or_file: either some code (i.e.: from pprint import pprint) or a file to be executed. + operation_fn_name: the name of the operation to execute after the exec (i.e.: pprint) + """ + expressionValue = getVariable(thread_id, frame_id, scope, attrs) + + try: + namespace = {'__name__': '<customOperation>'} + if style == "EXECFILE": + namespace['__file__'] = code_or_file + execfile(code_or_file, namespace, namespace) + else: # style == EXEC + namespace['__file__'] = '<customOperationCode>' + Exec(code_or_file, namespace, namespace) + + return str(namespace[operation_fn_name](expressionValue)) + except: + traceback.print_exc() + def evaluateExpression(thread_id, frame_id, expression, doExec): '''returns the result of the evaluated expression @@ -230,6 +294,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): updated_globals.update(frame.f_locals) #locals later because it has precedence over the actual globals try: + if doExec: try: #try to make it an eval (if it is an eval we can print it, otherwise we'll exec it and @@ -240,7 +305,7 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): pydevd_save_locals.save_locals(frame) else: result = eval(compiled, updated_globals, frame.f_locals) - if result is not None: #Only print if it's not None (as python does) + if result is not None: #Only print if it's not None (as python does) sys.stdout.write('%s\n' % (result,)) return @@ -251,7 +316,6 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): except Exception: s = StringIO() traceback.print_exc(file=s) - result = s.getvalue() try: @@ -265,6 +329,22 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): result = ExceptionOnEvaluate(result) + # Ok, we have the initial error message, but let's see if we're dealing with a name mangling error... + try: + if '__' in expression: + # Try to handle '__' name mangling... + split = expression.split('.') + curr = frame.f_locals.get(split[0]) + for entry in split[1:]: + if entry.startswith('__') and not hasattr(curr, entry): + entry = '_%s%s' % (curr.__class__.__name__, entry) + curr = getattr(curr, entry) + + result = curr + except: + pass + + return result finally: #Should not be kept alive if an exception happens and this frame is kept in the stack. @@ -273,22 +353,18 @@ def evaluateExpression(thread_id, frame_id, expression, doExec): def changeAttrExpression(thread_id, frame_id, attr, expression): '''Changes some attribute in a given frame. - @note: it will not (currently) work if we're not in the topmost frame (that's a python - deficiency -- and it appears that there is no way of making it currently work -- - will probably need some change to the python internals) ''' frame = findFrame(thread_id, frame_id) if frame is None: return - if isinstance(frame, DjangoTemplateFrame): - result = eval(expression, frame.f_globals, frame.f_locals) - frame.changeVariable(attr, result) - try: expression = expression.replace('@LINE@', '\n') - + if isinstance(frame, DjangoTemplateFrame): + result = eval(expression, frame.f_globals, frame.f_locals) + frame.changeVariable(attr, result) + return if attr[:7] == "Globals": attr = attr[8:] |