| """ pydevd_vars deals with variables: |
| resolution/conversion to XML. |
| """ |
| import pickle |
| from django_frame import DjangoTemplateFrame |
| from pydevd_constants import * #@UnusedWildImport |
| from types import * #@UnusedWildImport |
| |
| from pydevd_xml import * |
| |
| try: |
| from StringIO import StringIO |
| except ImportError: |
| from io import StringIO |
| import sys #@Reimport |
| |
| if USE_LIB_COPY: |
| import _pydev_threading as threading |
| else: |
| import threading |
| import pydevd_resolver |
| import traceback |
| |
| try: |
| from pydevd_exec import Exec |
| except: |
| from pydevd_exec2 import Exec |
| |
| #-------------------------------------------------------------------------- defining true and false for earlier versions |
| |
| 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 |
| |
| 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 |
| |
| def iterFrames(initialFrame): |
| """NO-YIELD VERSION: Iterates through all the frames starting at the specified frame (which will be the first returned item)""" |
| #cannot use yield |
| frames = [] |
| |
| while initialFrame is not None: |
| frames.append(initialFrame) |
| initialFrame = initialFrame.f_back |
| |
| return frames |
| |
| def dumpFrames(thread_id): |
| sys.stdout.write('dumping frames\n') |
| if thread_id != GetThreadId(threading.currentThread()): |
| raise VariableError("findFrame: must execute on same thread") |
| |
| curFrame = GetFrame() |
| for frame in iterFrames(curFrame): |
| sys.stdout.write('%s\n' % pickle.dumps(frame)) |
| |
| |
| #=============================================================================== |
| # AdditionalFramesContainer |
| #=============================================================================== |
| class AdditionalFramesContainer: |
| lock = threading.Lock() |
| additional_frames = {} #dict of dicts |
| |
| |
| def addAdditionalFrameById(thread_id, frames_by_id): |
| AdditionalFramesContainer.additional_frames[thread_id] = frames_by_id |
| |
| |
| def removeAdditionalFrameById(thread_id): |
| del AdditionalFramesContainer.additional_frames[thread_id] |
| |
| |
| |
| def findFrame(thread_id, frame_id): |
| """ returns a frame on the thread that has a given frame_id """ |
| if thread_id != GetThreadId(threading.currentThread()): |
| raise VariableError("findFrame: must execute on same thread") |
| |
| lookingFor = int(frame_id) |
| |
| if AdditionalFramesContainer.additional_frames: |
| if DictContains(AdditionalFramesContainer.additional_frames, thread_id): |
| frame = AdditionalFramesContainer.additional_frames[thread_id].get(lookingFor) |
| |
| if frame is not None: |
| return frame |
| |
| curFrame = GetFrame() |
| if frame_id == "*": |
| return curFrame # any frame is specified with "*" |
| |
| frameFound = None |
| |
| for frame in iterFrames(curFrame): |
| if lookingFor == id(frame): |
| frameFound = frame |
| del frame |
| break |
| |
| del frame |
| |
| #Important: python can hold a reference to the frame from the current context |
| #if an exception is raised, so, if we don't explicitly add those deletes |
| #we might have those variables living much more than we'd want to. |
| |
| #I.e.: sys.exc_info holding reference to frame that raises exception (so, other places |
| #need to call sys.exc_clear()) |
| del curFrame |
| |
| if frameFound is None: |
| msgFrames = '' |
| i = 0 |
| |
| for frame in iterFrames(GetFrame()): |
| i += 1 |
| msgFrames += str(id(frame)) |
| if i % 5 == 0: |
| msgFrames += '\n' |
| else: |
| msgFrames += ' - ' |
| |
| errMsg = '''findFrame: frame not found. |
| Looking for thread_id:%s, frame_id:%s |
| Current thread_id:%s, available frames: |
| %s |
| ''' % (thread_id, lookingFor, GetThreadId(threading.currentThread()), msgFrames) |
| |
| sys.stderr.write(errMsg) |
| return None |
| |
| return frameFound |
| |
| def resolveCompoundVariable(thread_id, frame_id, scope, attrs): |
| """ returns the value of the compound variable as a dictionary""" |
| 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 |
| else: |
| var = frame.f_locals |
| type, _typeName, resolver = getType(var) |
| try: |
| resolver.resolve(var, attrList[0]) |
| except: |
| var = frame.f_globals |
| |
| 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 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 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 |
| """ |
| frame = findFrame(thread_id, frame_id) |
| if frame is None: |
| return |
| |
| expression = str(expression.replace('@LINE@', '\n')) |
| |
| |
| #Not using frame.f_globals because of https://sourceforge.net/tracker2/?func=detail&aid=2541355&group_id=85796&atid=577329 |
| #(Names not resolved in generator expression in method) |
| #See message: http://mail.python.org/pipermail/python-list/2009-January/526522.html |
| updated_globals = {} |
| updated_globals.update(frame.f_globals) |
| 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 |
| #it will have whatever the user actually did) |
| compiled = compile(expression, '<string>', 'eval') |
| except: |
| Exec(expression, updated_globals, frame.f_locals) |
| else: |
| result = eval(compiled, updated_globals, frame.f_locals) |
| if result is not None: #Only print if it's not None (as python does) |
| sys.stdout.write('%s\n' % (result,)) |
| return |
| |
| else: |
| result = None |
| try: |
| result = eval(expression, updated_globals, frame.f_locals) |
| except Exception: |
| s = StringIO() |
| traceback.print_exc(file=s) |
| |
| result = s.getvalue() |
| |
| try: |
| try: |
| etype, value, tb = sys.exc_info() |
| result = value |
| finally: |
| etype = value = tb = None |
| except: |
| pass |
| |
| result = ExceptionOnEvaluate(result) |
| |
| return result |
| finally: |
| #Should not be kept alive if an exception happens and this frame is kept in the stack. |
| del updated_globals |
| del frame |
| |
| 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') |
| #tests (needs proposed patch in python accepted) |
| # if hasattr(frame, 'savelocals'): |
| # if attr in frame.f_locals: |
| # frame.f_locals[attr] = eval(expression, frame.f_globals, frame.f_locals) |
| # frame.savelocals() |
| # return |
| # |
| # elif attr in frame.f_globals: |
| # frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals) |
| # return |
| |
| |
| if attr[:7] == "Globals": |
| attr = attr[8:] |
| if attr in frame.f_globals: |
| frame.f_globals[attr] = eval(expression, frame.f_globals, frame.f_locals) |
| return frame.f_globals[attr] |
| else: |
| #default way (only works for changing it in the topmost frame) |
| result = eval(expression, frame.f_globals, frame.f_locals) |
| Exec('%s=%s' % (attr, expression), frame.f_globals, frame.f_locals) |
| return result |
| |
| |
| except Exception: |
| traceback.print_exc() |
| |
| |
| |
| |
| |