''' pydevd - a debugging daemon This is the daemon you launch for python remote debugging. Protocol: each command has a format: id\tsequence-num\ttext id: protocol command number sequence-num: each request has a sequence number. Sequence numbers originating at the debugger are odd, sequence numbers originating at the daemon are even. Every response uses the same sequence number as the request. payload: it is protocol dependent. When response is a complex structure, it is returned as XML. Each attribute value is urlencoded, and then the whole payload is urlencoded again to prevent stray characters corrupting protocol/xml encodings Commands: NUMBER NAME FROM* ARGUMENTS RESPONSE NOTE 100 series: program execution 101 RUN JAVA - - 102 LIST_THREADS JAVA RETURN with XML listing of all threads 103 THREAD_CREATE PYDB - XML with thread information 104 THREAD_KILL JAVA id (or * to exit) kills the thread PYDB id nofies JAVA that thread was killed 105 THREAD_SUSPEND JAVA XML of the stack, suspends the thread reason for suspension PYDB id notifies JAVA that thread was suspended 106 CMD_THREAD_RUN JAVA id resume the thread PYDB id \t reason notifies JAVA that thread was resumed 107 STEP_INTO JAVA thread_id 108 STEP_OVER JAVA thread_id 109 STEP_RETURN JAVA thread_id 110 GET_VARIABLE JAVA thread_id \t frame_id \t GET_VARIABLE with XML of var content FRAME|GLOBAL \t attributes* 111 SET_BREAK JAVA file/line of the breakpoint 112 REMOVE_BREAK JAVA file/line of the return 113 CMD_EVALUATE_EXPRESSION JAVA expression result of evaluating the expression 114 CMD_GET_FRAME JAVA request for frame contents 115 CMD_EXEC_EXPRESSION JAVA 116 CMD_WRITE_TO_CONSOLE PYDB 117 CMD_CHANGE_VARIABLE 118 CMD_RUN_TO_LINE 119 CMD_RELOAD_CODE 120 CMD_GET_COMPLETIONS JAVA 500 series diagnostics/ok 501 VERSION either Version string (1.0) Currently just used at startup 502 RETURN either Depends on caller - 900 series: errors 901 ERROR either - This is reserved for unexpected errors. * JAVA - remote debugger, the java end * PYDB - pydevd, the python end ''' from pydevd_constants import * #@UnusedWildImport import sys if USE_LIB_COPY: import _pydev_time as time import _pydev_threading as threading try: import _pydev_thread as thread except ImportError: import _thread as thread #Py3K changed it. import _pydev_Queue as _queue from _pydev_socket import socket from _pydev_socket import AF_INET, SOCK_STREAM from _pydev_socket import SHUT_RD, SHUT_WR else: import time import threading try: import thread except ImportError: import _thread as thread #Py3K changed it. try: import Queue as _queue except ImportError: import queue as _queue from socket import socket from socket import AF_INET, SOCK_STREAM from socket import SHUT_RD, SHUT_WR try: from urllib import quote, quote_plus, unquote, unquote_plus except: from urllib.parse import quote, quote_plus, unquote, unquote_plus #@Reimport @UnresolvedImport import pydevconsole import pydevd_vars import pydevd_tracing import pydevd_vm_type import pydevd_file_utils import traceback from pydevd_utils import quote_smart as quote, compare_object_attrs, cmp_to_key, to_string import pydev_log import _pydev_completer from pydevd_tracing import GetExceptionTracebackStr CMD_RUN = 101 CMD_LIST_THREADS = 102 CMD_THREAD_CREATE = 103 CMD_THREAD_KILL = 104 CMD_THREAD_SUSPEND = 105 CMD_THREAD_RUN = 106 CMD_STEP_INTO = 107 CMD_STEP_OVER = 108 CMD_STEP_RETURN = 109 CMD_GET_VARIABLE = 110 CMD_SET_BREAK = 111 CMD_REMOVE_BREAK = 112 CMD_EVALUATE_EXPRESSION = 113 CMD_GET_FRAME = 114 CMD_EXEC_EXPRESSION = 115 CMD_WRITE_TO_CONSOLE = 116 CMD_CHANGE_VARIABLE = 117 CMD_RUN_TO_LINE = 118 CMD_RELOAD_CODE = 119 CMD_GET_COMPLETIONS = 120 CMD_CONSOLE_EXEC = 121 CMD_ADD_EXCEPTION_BREAK = 122 CMD_REMOVE_EXCEPTION_BREAK = 123 CMD_LOAD_SOURCE = 124 CMD_ADD_DJANGO_EXCEPTION_BREAK = 125 CMD_REMOVE_DJANGO_EXCEPTION_BREAK = 126 CMD_SET_NEXT_STATEMENT = 127 CMD_SMART_STEP_INTO = 128 CMD_EXIT = 129 CMD_SIGNATURE_CALL_TRACE = 130 CMD_VERSION = 501 CMD_RETURN = 502 CMD_ERROR = 901 ID_TO_MEANING = { '101':'CMD_RUN', '102':'CMD_LIST_THREADS', '103':'CMD_THREAD_CREATE', '104':'CMD_THREAD_KILL', '105':'CMD_THREAD_SUSPEND', '106':'CMD_THREAD_RUN', '107':'CMD_STEP_INTO', '108':'CMD_STEP_OVER', '109':'CMD_STEP_RETURN', '110':'CMD_GET_VARIABLE', '111':'CMD_SET_BREAK', '112':'CMD_REMOVE_BREAK', '113':'CMD_EVALUATE_EXPRESSION', '114':'CMD_GET_FRAME', '115':'CMD_EXEC_EXPRESSION', '116':'CMD_WRITE_TO_CONSOLE', '117':'CMD_CHANGE_VARIABLE', '118':'CMD_RUN_TO_LINE', '119':'CMD_RELOAD_CODE', '120':'CMD_GET_COMPLETIONS', '121':'CMD_CONSOLE_EXEC', '122':'CMD_ADD_EXCEPTION_BREAK', '123':'CMD_REMOVE_EXCEPTION_BREAK', '124':'CMD_LOAD_SOURCE', '125':'CMD_ADD_DJANGO_EXCEPTION_BREAK', '126':'CMD_REMOVE_DJANGO_EXCEPTION_BREAK', '127':'CMD_SET_NEXT_STATEMENT', '128':'CMD_SMART_STEP_INTO', '129': 'CMD_EXIT', '130': 'CMD_SIGNATURE_CALL_TRACE', '501':'CMD_VERSION', '502':'CMD_RETURN', '901':'CMD_ERROR', } MAX_IO_MSG_SIZE = 1000 #if the io is too big, we'll not send all (could make the debugger too non-responsive) #this number can be changed if there's need to do so VERSION_STRING = "@@BUILD_NUMBER@@" from _pydev_filesystem_encoding import getfilesystemencoding file_system_encoding = getfilesystemencoding() #--------------------------------------------------------------------------------------------------- UTILITIES #======================================================================================================================= # PydevdLog #======================================================================================================================= def PydevdLog(level, *args): """ levels are: 0 most serious warnings/errors 1 warnings/significant events 2 informational trace """ if level <= DebugInfoHolder.DEBUG_TRACE_LEVEL: #yes, we can have errors printing if the console of the program has been finished (and we're still trying to print something) try: sys.stderr.write('%s\n' % (args,)) except: pass #======================================================================================================================= # GlobalDebuggerHolder #======================================================================================================================= class GlobalDebuggerHolder: ''' Holder for the global debugger. ''' globalDbg = None #======================================================================================================================= # GetGlobalDebugger #======================================================================================================================= def GetGlobalDebugger(): return GlobalDebuggerHolder.globalDbg #======================================================================================================================= # SetGlobalDebugger #======================================================================================================================= def SetGlobalDebugger(dbg): GlobalDebuggerHolder.globalDbg = dbg #------------------------------------------------------------------- ACTUAL COMM #======================================================================================================================= # PyDBDaemonThread #======================================================================================================================= class PyDBDaemonThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) self.setDaemon(True) self.killReceived = False self.dontTraceMe = True def run(self): if sys.platform.startswith("java"): import org.python.core as PyCore #@UnresolvedImport ss = PyCore.PySystemState() # Note: Py.setSystemState() affects only the current thread. PyCore.Py.setSystemState(ss) self.OnRun() def OnRun(self): raise NotImplementedError('Should be reimplemented by: %s' % self.__class__) def doKillPydevThread(self): #that was not working very well because jython gave some socket errors self.killReceived = True def stopTrace(self): if self.dontTraceMe: pydevd_tracing.SetTrace(None) # no debugging on this thread #======================================================================================================================= # ReaderThread #======================================================================================================================= class ReaderThread(PyDBDaemonThread): """ reader thread reads and dispatches commands in an infinite loop """ def __init__(self, sock): PyDBDaemonThread.__init__(self) self.sock = sock self.setName("pydevd.Reader") def doKillPydevThread(self): #We must close the socket so that it doesn't stay halted there. self.killReceived = True try: self.sock.shutdown(SHUT_RD) #shotdown the socket for read except: #just ignore that pass def OnRun(self): self.stopTrace() buffer = "" try: while not self.killReceived: try: r = self.sock.recv(1024) except: if not self.killReceived: self.handleExcept() return #Finished communication. #Note: the java backend is always expected to pass utf-8 encoded strings. We now work with unicode #internally and thus, we may need to convert to the actual encoding where needed (i.e.: filenames #on python 2 may need to be converted to the filesystem encoding). if hasattr(r, 'decode'): r = r.decode('utf-8') buffer += r if DebugInfoHolder.DEBUG_RECORD_SOCKET_READS: pydev_log.debug('received >>%s<<\n' % (buffer,)) if len(buffer) == 0: self.handleExcept() break while buffer.find('\n') != -1: command, buffer = buffer.split('\n', 1) args = command.split('\t', 2) try: cmd_id = int(args[0]) pydev_log.debug('Received command: %s %s\n' % (ID_TO_MEANING.get(str(cmd_id), '???'), command,)) self.processCommand(cmd_id, int(args[1]), args[2]) except: traceback.print_exc() sys.stderr.write("Can't process net command: %s\n" % command) sys.stderr.flush() except: traceback.print_exc() self.handleExcept() def handleExcept(self): GlobalDebuggerHolder.globalDbg.FinishDebuggingSession() def processCommand(self, cmd_id, seq, text): GlobalDebuggerHolder.globalDbg.processNetCommand(cmd_id, seq, text) #----------------------------------------------------------------------------------- SOCKET UTILITIES - WRITER #======================================================================================================================= # WriterThread #======================================================================================================================= class WriterThread(PyDBDaemonThread): """ writer thread writes out the commands in an infinite loop """ def __init__(self, sock): PyDBDaemonThread.__init__(self) self.setDaemon(False) #writer isn't daemon to be able to deliver all messages after main thread terminated self.sock = sock self.setName("pydevd.Writer") self.cmdQueue = _queue.Queue() if pydevd_vm_type.GetVmType() == 'python': self.timeout = 0 else: self.timeout = 0.1 def addCommand(self, cmd): """ cmd is NetCommand """ if not self.killReceived: #we don't take new data after everybody die self.cmdQueue.put(cmd) def OnRun(self): """ just loop and write responses """ self.stopTrace() try: while True: try: try: cmd = self.cmdQueue.get(1, 0.1) except _queue.Empty: if self.killReceived: try: self.sock.shutdown(SHUT_WR) self.sock.close() except: pass return #break if queue is empty and killReceived else: continue except: #PydevdLog(0, 'Finishing debug communication...(1)') #when liberating the thread here, we could have errors because we were shutting down #but the thread was still not liberated return out = cmd.getOutgoing() if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 1: out_message = 'sending cmd --> ' out_message += "%20s" % ID_TO_MEANING.get(out[:3], 'UNKNOWN') out_message += ' ' out_message += unquote(unquote(out)).replace('\n', ' ') try: sys.stderr.write('%s\n' % (out_message,)) except: pass if IS_PY3K: out = bytearray(out, 'utf-8') self.sock.send(out) #TODO: this does not guarantee that all message are sent (and jython does not have a send all) if cmd.id == CMD_EXIT: break if time is None: break #interpreter shutdown time.sleep(self.timeout) except Exception: GlobalDebuggerHolder.globalDbg.FinishDebuggingSession() if DebugInfoHolder.DEBUG_TRACE_LEVEL >= 0: traceback.print_exc() #--------------------------------------------------- CREATING THE SOCKET THREADS #======================================================================================================================= # StartServer #======================================================================================================================= def StartServer(port): """ binds to a port, waits for the debugger to connect """ s = socket(AF_INET, SOCK_STREAM) s.bind(('', port)) s.listen(1) newSock, _addr = s.accept() return newSock #======================================================================================================================= # StartClient #======================================================================================================================= def StartClient(host, port): """ connects to a host/port """ PydevdLog(1, "Connecting to ", host, ":", str(port)) s = socket(AF_INET, SOCK_STREAM) MAX_TRIES = 100 i = 0 while i_=" \t') return str(cmd) + '\t' + str(seq) + '\t' + encoded + "\n" #======================================================================================================================= # NetCommandFactory #======================================================================================================================= class NetCommandFactory: def __init_(self): self.next_seq = 0 def threadToXML(self, thread): """ thread information as XML """ name = pydevd_vars.makeValidXmlValue(thread.getName()) cmdText = '' % (quote(name), GetThreadId(thread)) return cmdText def makeErrorMessage(self, seq, text): cmd = NetCommand(CMD_ERROR, seq, text) if DebugInfoHolder.DEBUG_TRACE_LEVEL > 2: sys.stderr.write("Error: %s" % (text,)) return cmd def makeThreadCreatedMessage(self, thread): cmdText = "" + self.threadToXML(thread) + "" return NetCommand(CMD_THREAD_CREATE, 0, cmdText) def makeCustomFrameCreatedMessage(self, frameId, frameDescription): frameDescription = pydevd_vars.makeValidXmlValue(frameDescription) cmdText = '' % (frameDescription, frameId) return NetCommand(CMD_THREAD_CREATE, 0, cmdText) def makeListThreadsMessage(self, seq): """ returns thread listing as XML """ try: t = threading.enumerate() cmdText = "" for i in t: if t.isAlive(): cmdText += self.threadToXML(i) cmdText += "" return NetCommand(CMD_RETURN, seq, cmdText) except: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) def makeVariableChangedMessage(self, seq, payload): # notify debugger that value was changed successfully return NetCommand(CMD_RETURN, seq, payload) def makeIoMessage(self, v, ctx, dbg=None): ''' @param v: the message to pass to the debug server @param ctx: 1 for stdio 2 for stderr @param dbg: If not none, add to the writer ''' try: if len(v) > MAX_IO_MSG_SIZE: v = v[0:MAX_IO_MSG_SIZE] v += '...' v = pydevd_vars.makeValidXmlValue(quote(v, '/>_= \t')) net = NetCommand(str(CMD_WRITE_TO_CONSOLE), 0, '' % (v, ctx)) except: net = self.makeErrorMessage(0, GetExceptionTracebackStr()) if dbg: dbg.writer.addCommand(net) return net def makeVersionMessage(self, seq): try: return NetCommand(CMD_VERSION, seq, VERSION_STRING) except: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) def makeThreadKilledMessage(self, id): try: return NetCommand(CMD_THREAD_KILL, 0, str(id)) except: return self.makeErrorMessage(0, GetExceptionTracebackStr()) def makeThreadSuspendMessage(self, thread_id, frame, stop_reason, message): """ """ try: cmdTextList = [""] if message: message = pydevd_vars.makeValidXmlValue(str(message)) cmdTextList.append('' % (thread_id, stop_reason, message)) curFrame = frame try: while curFrame: #print cmdText myId = str(id(curFrame)) #print "id is ", myId if curFrame.f_code is None: break #Iron Python sometimes does not have it! myName = curFrame.f_code.co_name #method name (if in method) or ? if global if myName is None: break #Iron Python sometimes does not have it! #print "name is ", myName filename, base = pydevd_file_utils.GetFilenameAndBase(curFrame) myFile = pydevd_file_utils.NormFileToClient(filename) if file_system_encoding.lower() != "utf-8" and hasattr(myFile, "decode"): # myFile is a byte string encoded using the file system encoding # convert it to utf8 myFile = myFile.decode(file_system_encoding).encode("utf-8") #print "file is ", myFile #myFile = inspect.getsourcefile(curFrame) or inspect.getfile(frame) myLine = str(curFrame.f_lineno) #print "line is ", myLine #the variables are all gotten 'on-demand' #variables = pydevd_vars.frameVarsToXML(curFrame.f_locals) variables = '' cmdTextList.append('"' % (quote(myFile, '/>_= \t'), myLine)) cmdTextList.append(variables) cmdTextList.append("") curFrame = curFrame.f_back except : traceback.print_exc() cmdTextList.append("") cmdText = ''.join(cmdTextList) return NetCommand(CMD_THREAD_SUSPEND, 0, cmdText) except: return self.makeErrorMessage(0, GetExceptionTracebackStr()) def makeThreadRunMessage(self, id, reason): try: return NetCommand(CMD_THREAD_RUN, 0, str(id) + "\t" + str(reason)) except: return self.makeErrorMessage(0, GetExceptionTracebackStr()) def makeGetVariableMessage(self, seq, payload): try: return NetCommand(CMD_GET_VARIABLE, seq, payload) except Exception: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) def makeGetFrameMessage(self, seq, payload): try: return NetCommand(CMD_GET_FRAME, seq, payload) except Exception: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) def makeEvaluateExpressionMessage(self, seq, payload): try: return NetCommand(CMD_EVALUATE_EXPRESSION, seq, payload) except Exception: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) def makeGetCompletionsMessage(self, seq, payload): try: return NetCommand(CMD_GET_COMPLETIONS, seq, payload) except Exception: return self.makeErrorMessage(seq, GetExceptionTracebackStr()) def makeLoadSourceMessage(self, seq, source, dbg=None): try: net = NetCommand(CMD_LOAD_SOURCE, seq, '%s' % source) except: net = self.makeErrorMessage(0, GetExceptionTracebackStr()) if dbg: dbg.writer.addCommand(net) return net def makeExitMessage(self): try: net = NetCommand(CMD_EXIT, 0, '') except: net = self.makeErrorMessage(0, GetExceptionTracebackStr()) return net INTERNAL_TERMINATE_THREAD = 1 INTERNAL_SUSPEND_THREAD = 2 #======================================================================================================================= # InternalThreadCommand #======================================================================================================================= class InternalThreadCommand: """ internal commands are generated/executed by the debugger. The reason for their existence is that some commands have to be executed on specific threads. These are the InternalThreadCommands that get get posted to PyDB.cmdQueue. """ def canBeExecutedBy(self, thread_id): '''By default, it must be in the same thread to be executed ''' return self.thread_id == thread_id def doIt(self, dbg): raise NotImplementedError("you have to override doIt") class ReloadCodeCommand(InternalThreadCommand): def __init__(self, module_name, thread_id): self.thread_id = thread_id self.module_name = module_name self.executed = False self.lock = threading.Lock() def canBeExecutedBy(self, thread_id): if self.thread_id == '*': return True #Any thread can execute it! return InternalThreadCommand.canBeExecutedBy(self, thread_id) def doIt(self, dbg): self.lock.acquire() try: if self.executed: return self.executed = True finally: self.lock.release() module_name = self.module_name if not DictContains(sys.modules, module_name): if '.' in module_name: new_module_name = module_name.split('.')[-1] if DictContains(sys.modules, new_module_name): module_name = new_module_name if not DictContains(sys.modules, module_name): sys.stderr.write('pydev debugger: Unable to find module to reload: "' + module_name + '".\n') # Too much info... # sys.stderr.write('pydev debugger: This usually means you are trying to reload the __main__ module (which cannot be reloaded).\n') else: sys.stderr.write('pydev debugger: Start reloading module: "' + module_name + '" ... \n') import pydevd_reload if pydevd_reload.xreload(sys.modules[module_name]): sys.stderr.write('pydev debugger: reload finished\n') else: sys.stderr.write('pydev debugger: reload finished without applying any change\n') #======================================================================================================================= # InternalTerminateThread #======================================================================================================================= class InternalTerminateThread(InternalThreadCommand): def __init__(self, thread_id): self.thread_id = thread_id def doIt(self, dbg): PydevdLog(1, "killing ", str(self.thread_id)) cmd = dbg.cmdFactory.makeThreadKilledMessage(self.thread_id) dbg.writer.addCommand(cmd) #======================================================================================================================= # InternalRunThread #======================================================================================================================= class InternalRunThread(InternalThreadCommand): def __init__(self, thread_id): self.thread_id = thread_id def doIt(self, dbg): t = PydevdFindThreadById(self.thread_id) if t: t.additionalInfo.pydev_step_cmd = None t.additionalInfo.pydev_step_stop = None t.additionalInfo.pydev_state = STATE_RUN #======================================================================================================================= # InternalStepThread #======================================================================================================================= class InternalStepThread(InternalThreadCommand): def __init__(self, thread_id, cmd_id): self.thread_id = thread_id self.cmd_id = cmd_id def doIt(self, dbg): t = PydevdFindThreadById(self.thread_id) if t: t.additionalInfo.pydev_step_cmd = self.cmd_id t.additionalInfo.pydev_state = STATE_RUN #======================================================================================================================= # InternalSetNextStatementThread #======================================================================================================================= class InternalSetNextStatementThread(InternalThreadCommand): def __init__(self, thread_id, cmd_id, line, func_name): self.thread_id = thread_id self.cmd_id = cmd_id self.line = line self.func_name = func_name def doIt(self, dbg): t = PydevdFindThreadById(self.thread_id) if t: t.additionalInfo.pydev_step_cmd = self.cmd_id t.additionalInfo.pydev_next_line = int(self.line) t.additionalInfo.pydev_func_name = self.func_name t.additionalInfo.pydev_state = STATE_RUN #======================================================================================================================= # InternalGetVariable #======================================================================================================================= class InternalGetVariable(InternalThreadCommand): """ gets the value of a variable """ def __init__(self, seq, thread_id, frame_id, scope, attrs): self.sequence = seq self.thread_id = thread_id self.frame_id = frame_id self.scope = scope self.attributes = attrs def doIt(self, dbg): """ Converts request into python variable """ try: xml = "" valDict = pydevd_vars.resolveCompoundVariable(self.thread_id, self.frame_id, self.scope, self.attributes) if valDict is None: valDict = {} keys = valDict.keys() if hasattr(keys, 'sort'): keys.sort(compare_object_attrs) #Python 3.0 does not have it else: if IS_PY3K: keys = sorted(keys, key=cmp_to_key(compare_object_attrs)) #Jython 2.1 does not have it (and all must be compared as strings). else: keys = sorted(keys, cmp=compare_object_attrs) #Jython 2.1 does not have it (and all must be compared as strings). for k in keys: xml += pydevd_vars.varToXML(valDict[k], to_string(k)) xml += "" cmd = dbg.cmdFactory.makeGetVariableMessage(self.sequence, xml) dbg.writer.addCommand(cmd) except Exception: cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving variables " + GetExceptionTracebackStr()) dbg.writer.addCommand(cmd) #======================================================================================================================= # InternalChangeVariable #======================================================================================================================= class InternalChangeVariable(InternalThreadCommand): """ changes the value of a variable """ def __init__(self, seq, thread_id, frame_id, scope, attr, expression): self.sequence = seq self.thread_id = thread_id self.frame_id = frame_id self.scope = scope self.attr = attr self.expression = expression def doIt(self, dbg): """ Converts request into python variable """ try: result = pydevd_vars.changeAttrExpression(self.thread_id, self.frame_id, self.attr, self.expression) xml = "" xml += pydevd_vars.varToXML(result, "") xml += "" cmd = dbg.cmdFactory.makeVariableChangedMessage(self.sequence, xml) dbg.writer.addCommand(cmd) except Exception: cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error changing variable attr:%s expression:%s traceback:%s" % (self.attr, self.expression, GetExceptionTracebackStr())) dbg.writer.addCommand(cmd) #======================================================================================================================= # InternalGetFrame #======================================================================================================================= class InternalGetFrame(InternalThreadCommand): """ gets the value of a variable """ def __init__(self, seq, thread_id, frame_id): self.sequence = seq self.thread_id = thread_id self.frame_id = frame_id def doIt(self, dbg): """ Converts request into python variable """ try: frame = pydevd_vars.findFrame(self.thread_id, self.frame_id) if frame is not None: xml = "" xml += pydevd_vars.frameVarsToXML(frame.f_locals) del frame xml += "" cmd = dbg.cmdFactory.makeGetFrameMessage(self.sequence, xml) dbg.writer.addCommand(cmd) else: #pydevd_vars.dumpFrames(self.thread_id) #don't print this error: frame not found: means that the client is not synchronized (but that's ok) cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id)) dbg.writer.addCommand(cmd) except: cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error resolving frame: %s from thread: %s" % (self.frame_id, self.thread_id)) dbg.writer.addCommand(cmd) #======================================================================================================================= # InternalEvaluateExpression #======================================================================================================================= class InternalEvaluateExpression(InternalThreadCommand): """ gets the value of a variable """ def __init__(self, seq, thread_id, frame_id, expression, doExec, doTrim): self.sequence = seq self.thread_id = thread_id self.frame_id = frame_id self.expression = expression self.doExec = doExec self.doTrim = doTrim def doIt(self, dbg): """ Converts request into python variable """ try: result = pydevd_vars.evaluateExpression(self.thread_id, self.frame_id, self.expression, self.doExec) xml = "" xml += pydevd_vars.varToXML(result, "", self.doTrim) xml += "" cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml) dbg.writer.addCommand(cmd) except: exc = GetExceptionTracebackStr() sys.stderr.write('%s\n' % (exc,)) cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc) dbg.writer.addCommand(cmd) #======================================================================================================================= # InternalGetCompletions #======================================================================================================================= class InternalGetCompletions(InternalThreadCommand): """ Gets the completions in a given scope """ def __init__(self, seq, thread_id, frame_id, act_tok): self.sequence = seq self.thread_id = thread_id self.frame_id = frame_id self.act_tok = act_tok def doIt(self, dbg): """ Converts request into completions """ try: remove_path = None try: frame = pydevd_vars.findFrame(self.thread_id, self.frame_id) if frame is not None: msg = _pydev_completer.GenerateCompletionsAsXML(frame, self.act_tok) cmd = dbg.cmdFactory.makeGetCompletionsMessage(self.sequence, msg) dbg.writer.addCommand(cmd) else: cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "InternalGetCompletions: Frame not found: %s from thread: %s" % (self.frame_id, self.thread_id)) dbg.writer.addCommand(cmd) finally: if remove_path is not None: sys.path.remove(remove_path) except: exc = GetExceptionTracebackStr() sys.stderr.write('%s\n' % (exc,)) cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating expression " + exc) dbg.writer.addCommand(cmd) #======================================================================================================================= # InternalConsoleExec #======================================================================================================================= class InternalConsoleExec(InternalThreadCommand): """ gets the value of a variable """ def __init__(self, seq, thread_id, frame_id, expression): self.sequence = seq self.thread_id = thread_id self.frame_id = frame_id self.expression = expression def doIt(self, dbg): """ Converts request into python variable """ pydev_start_new_thread = None try: try: pydev_start_new_thread = thread.start_new_thread thread.start_new_thread = thread._original_start_new_thread #don't trace new threads created by console command thread.start_new = thread._original_start_new_thread result = pydevconsole.consoleExec(self.thread_id, self.frame_id, self.expression) xml = "" xml += pydevd_vars.varToXML(result, "") xml += "" cmd = dbg.cmdFactory.makeEvaluateExpressionMessage(self.sequence, xml) dbg.writer.addCommand(cmd) except: exc = GetExceptionTracebackStr() sys.stderr.write('%s\n' % (exc,)) cmd = dbg.cmdFactory.makeErrorMessage(self.sequence, "Error evaluating console expression " + exc) dbg.writer.addCommand(cmd) finally: thread.start_new_thread = pydev_start_new_thread thread.start_new = pydev_start_new_thread sys.stderr.flush() sys.stdout.flush() #======================================================================================================================= # PydevdFindThreadById #======================================================================================================================= def PydevdFindThreadById(thread_id): try: # there was a deadlock here when I did not remove the tracing function when thread was dead threads = threading.enumerate() for i in threads: tid = GetThreadId(i) if thread_id == tid or thread_id.endswith('|' + tid): return i sys.stderr.write("Could not find thread %s\n" % thread_id) sys.stderr.write("Available: %s\n" % [GetThreadId(t) for t in threads]) sys.stderr.flush() except: traceback.print_exc() return None