diff -r cd4e2cab7eb2 -r c99695c0f13a DebugClients/Python/DebugClientBase.py --- a/DebugClients/Python/DebugClientBase.py Sun Oct 06 17:27:53 2013 +0200 +++ b/DebugClients/Python/DebugClientBase.py Sun Oct 06 18:02:21 2013 +0200 @@ -29,7 +29,7 @@ DebugClientInstance = None -################################################################################ +############################################################################### def DebugClientRawInput(prompt="", echo=1): @@ -56,7 +56,7 @@ DebugClientOrigRawInput = __main__.__builtins__.__dict__['raw_input'] __main__.__builtins__.__dict__['raw_input'] = DebugClientRawInput -################################################################################ +############################################################################### def DebugClientInput(prompt=""): @@ -82,7 +82,7 @@ DebugClientOrigInput = __main__.__builtins__.__dict__['input'] __main__.__builtins__.__dict__['input'] = DebugClientInput -################################################################################ +############################################################################### def DebugClientFork(): @@ -101,7 +101,7 @@ DebugClientOrigFork = os.fork os.fork = DebugClientFork -################################################################################ +############################################################################### def DebugClientClose(fd): @@ -120,7 +120,7 @@ DebugClientOrigClose = os.close os.close = DebugClientClose -################################################################################ +############################################################################### def DebugClientSetRecursionLimit(limit): @@ -139,15 +139,15 @@ sys.setrecursionlimit = DebugClientSetRecursionLimit DebugClientSetRecursionLimit(sys.getrecursionlimit()) -################################################################################ +############################################################################### class DebugClientBase(object): """ Class implementing the client side of the debugger. - It provides access to the Python interpeter from a debugger running in another - process whether or not the Qt event loop is running. + It provides access to the Python interpeter from a debugger running in + another process whether or not the Qt event loop is running. The protocol between the debugger and the client assumes that there will be a single source of debugger commands and a single source of Python @@ -160,12 +160,11 @@ See DebugProtocol.py for a listing of valid protocol tokens. A Python statement consists of the statement to execute, followed (in a - separate line) by >OK?<. If the statement was incomplete then the response - is >Continue<. If there was an exception then the response is - >Exception<. - Otherwise the response is >OK<. The reason for the >OK?< part is to - provide a sentinal (ie. the responding >OK<) after any possible output as a - result of executing the command. + separate line) by >OK?<. If the statement was incomplete then the + response is >Continue<. If there was an exception then the response + is >Exception<. Otherwise the response is >OK<. The reason + for the >OK?< part is to provide a sentinal (ie. the responding + >OK<) after any possible output as a result of executing the command. The client may send any other lines at any other time which should be interpreted as program output. @@ -174,8 +173,8 @@ The client may close the session at any time as a result of the script being debugged closing or crashing. - <b>Note</b>: This class is meant to be subclassed by individual DebugClient classes. - Do not instantiate it directly. + <b>Note</b>: This class is meant to be subclassed by individual + DebugClient classes. Do not instantiate it directly. """ clientCapabilities = DebugClientCapabilities.HasAll @@ -193,7 +192,8 @@ # dictionary of all threads running self.threads = {} - # the "current" thread, basically the thread we are at a breakpoint for. + # the "current" thread, basically the thread we are at a + # breakpoint for. self.currentThread = self # special objects representing the main scripts thread and frame @@ -295,7 +295,8 @@ This is just an empty function and is overridden in the threaded debugger. - @param target the start function of the target thread (i.e. the user code) + @param target the start function of the target thread (i.e. the user + code) @param args arguments to pass to target @param kwargs keyword arguments to pass to target @param mainThread non-zero, if we are attaching to the already @@ -309,7 +310,8 @@ Public method to send the list of threads. """ threadList = [] - if self.threads and self.currentThread: # indication for the threaded debugger + if self.threads and self.currentThread: + # indication for the threaded debugger currentId = self.currentThread.get_ident() for t in self.threads.values(): d = {} @@ -336,7 +338,8 @@ @param echo Flag indicating echoing of the input (boolean) @return the entered string """ - self.write("%s%s\n" % (DebugProtocol.ResponseRaw, unicode((prompt, echo)))) + self.write("%s%s\n" % (DebugProtocol.ResponseRaw, + unicode((prompt, echo)))) self.inRawMode = 1 self.eventLoop(True) return self.rawLine @@ -360,7 +363,8 @@ def sessionClose(self, exit=1): """ - Public method to close the session with the debugger and optionally terminate. + Public method to close the session with the debugger and optionally + terminate. @param exit flag indicating to terminate (boolean) """ @@ -388,8 +392,8 @@ """ Public method to handle the receipt of a complete line. - It first looks for a valid protocol token at the start of the line. Thereafter - it trys to execute the lines accumulated so far. + It first looks for a valid protocol token at the start of the line. + Thereafter it trys to execute the lines accumulated so far. @param line the received line """ @@ -426,7 +430,8 @@ self.setCurrentThread(tid) self.write(DebugProtocol.ResponseThreadSet + '\n') stack = self.currentThread.getStack() - self.write('%s%s\n' % (DebugProtocol.ResponseStack, unicode(stack))) + self.write('%s%s\n' % (DebugProtocol.ResponseStack, + unicode(stack))) return if cmd == DebugProtocol.RequestStep: @@ -471,7 +476,8 @@ if self.debugging: self.callTraceEnabled = callTraceEnabled else: - self.__newCallTraceEnabled = callTraceEnabled # remember for later + self.__newCallTraceEnabled = callTraceEnabled + # remember for later return if cmd == DebugProtocol.RequestEnv: @@ -512,21 +518,24 @@ # we report on all unhandled exceptions sys.excepthook = self.__unhandled_exception - # clear all old breakpoints, they'll get set after we have started + # clear all old breakpoints, they'll get set after we + # have started self.mainThread.clear_all_breaks() self.mainThread.tracePython = tracePython # This will eventually enter a local event loop. - # Note the use of backquotes to cause a repr of self.running. The - # need for this is on Windows os where backslash is the path separator. - # They will get inadvertantly stripped away during the eval causing - # IOErrors, if self.running is passed as a normal str. + # Note the use of backquotes to cause a repr of self.running. + # The need for this is on Windows os where backslash is the + # path separator. They will get inadvertantly stripped away + # during the eval causing IOErrors, if self.running is passed + # as a normal str. self.debugMod.__dict__['__file__'] = self.running sys.modules['__main__'] = self.debugMod self.callTraceEnabled = self.__newCallTraceEnabled - res = self.mainThread.run('execfile(' + repr(self.running) + ')', - self.debugMod.__dict__) + res = self.mainThread.run( + 'execfile(' + repr(self.running) + ')', + self.debugMod.__dict__) self.progTerminated(res) return @@ -663,7 +672,8 @@ compile(cond, '<string>', 'eval') except SyntaxError: self.write('%s%s,%d\n' % \ - (DebugProtocol.ResponseBPConditionError, fn, line)) + (DebugProtocol.ResponseBPConditionError, fn, + line)) return self.mainThread.set_break(fn, line, temporary, cond) else: @@ -741,8 +751,9 @@ if cmd == DebugProtocol.RequestEval: try: - value = eval(arg, self.currentThread.getCurrentFrame().f_globals, - self.currentThread.getCurrentFrameLocals()) + value = eval( + arg, self.currentThread.getCurrentFrame().f_globals, + self.currentThread.getCurrentFrameLocals()) except: # Report the exception and the traceback try: @@ -806,7 +817,8 @@ return if cmd == DebugProtocol.RequestCapabilities: - self.write('%s%d, "Python"\n' % (DebugProtocol.ResponseCapabilities, + self.write('%s%d, "Python"\n' % ( + DebugProtocol.ResponseCapabilities, self.__clientCapabilities())) return @@ -908,7 +920,8 @@ except (OverflowError, SyntaxError, ValueError): # Report the exception sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() - map(self.write, traceback.format_exception_only(sys.last_type, sys.last_value)) + map(self.write, traceback.format_exception_only( + sys.last_type, sys.last_value)) self.buffer = '' else: if code is None: @@ -938,7 +951,8 @@ cf = cf.f_back frmnr -= 1 _globals = cf.f_globals - _locals = self.currentThread.getCurrentFrameLocals() + _locals = \ + self.currentThread.getCurrentFrameLocals() # reset sys.stdout to our redirector (unconditionally) if "sys" in _globals: __stdout = _globals["sys"].stdout @@ -987,7 +1001,8 @@ pass return self.clientCapabilities except ImportError: - return self.clientCapabilities & ~DebugClientCapabilities.HasProfiler + return (self.clientCapabilities & + ~DebugClientCapabilities.HasProfiler) def write(self, s): """ @@ -1095,10 +1110,12 @@ being debugged redirects them itself. @param port the port number to connect to (int) - @param remoteAddress the network address of the debug server host (string) - @param redirect flag indicating redirection of stdin, stdout and stderr (boolean) + @param remoteAddress the network address of the debug server host + (string) + @param redirect flag indicating redirection of stdin, stdout and + stderr (boolean) """ - if remoteAddress is None: # default: 127.0.0.1 + if remoteAddress is None: # default: 127.0.0.1 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((DebugProtocol.DebugAddress, port)) else: @@ -1106,13 +1123,13 @@ remoteAddress, index = remoteAddress.split("@@i") else: index = 0 - if ":" in remoteAddress: # IPv6 + if ":" in remoteAddress: # IPv6 sockaddr = socket.getaddrinfo( remoteAddress, port, 0, 0, socket.SOL_TCP)[0][-1] sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) sockaddr = sockaddr[:-1] + (int(index),) sock.connect(sockaddr) - else: # IPv4 + else: # IPv4 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((remoteAddress, port)) @@ -1185,7 +1202,8 @@ Public method to check if a file should be skipped. @param fn filename to be checked - @return non-zero if fn represents a file we are 'skipping', zero otherwise. + @return non-zero if fn represents a file we are 'skipping', + zero otherwise. """ if self.mainThread.tracePython: # trace into Python library return 0 @@ -1237,9 +1255,11 @@ """ Private method to return the variables of a frame to the debug server. - @param frmnr distance of frame reported on. 0 is the current frame (int) + @param frmnr distance of frame reported on. 0 is the current frame + (int) @param scope 1 to report global variables, 0 for local variables (int) - @param filter the indices of variable types to be filtered (list of int) + @param filter the indices of variable types to be filtered (list of + int) """ if self.currentThread is None: return @@ -1272,16 +1292,20 @@ vlist = self.__formatVariablesList(keylist, dict, scope, filter) varlist.extend(vlist) - self.write('%s%s\n' % (DebugProtocol.ResponseVariables, unicode(varlist))) + self.write('%s%s\n' % ( + DebugProtocol.ResponseVariables, unicode(varlist))) def __dumpVariable(self, var, frmnr, scope, filter): """ Private method to return the variables of a frame to the debug server. - @param var list encoded name of the requested variable (list of strings) - @param frmnr distance of frame reported on. 0 is the current frame (int) + @param var list encoded name of the requested variable + (list of strings) + @param frmnr distance of frame reported on. 0 is the current frame + (int) @param scope 1 to report global variables, 0 for local variables (int) - @param filter the indices of variable types to be filtered (list of int) + @param filter the indices of variable types to be filtered + (list of int) """ if self.currentThread is None: return @@ -1389,7 +1413,8 @@ if "PyQt4." in str(type(obj)): qtVariable = True qvar = obj - qvtype = ("%s" % type(qvar))[1:-1].split()[1][1:-1] + qvtype = ("%s" % type(qvar))[1:-1]\ + .split()[1][1:-1] except: pass try: @@ -1414,7 +1439,8 @@ if "PyQt4." in str(type(obj)): qtVariable = True qvar = obj - qvtype = ("%s" % type(qvar))[1:-1].split()[1][1:-1] + qvtype = ("%s" % type(qvar))[1:-1]\ + .split()[1][1:-1] except: pass else: @@ -1426,7 +1452,8 @@ if "PyQt4." in str(type(obj)): qtVariable = True qvar = obj - qvtype = ("%s" % type(qvar))[1:-1].split()[1][1:-1] + qvtype = ("%s" % type(qvar))[1:-1]\ + .split()[1][1:-1] except: pass try: @@ -1442,7 +1469,8 @@ if "PyQt4." in str(type(obj)): qtVariable = True qvar = obj - qvtype = ("%s" % type(qvar))[1:-1].split()[1][1:-1] + qvtype = ("%s" % type(qvar))[1:-1]\ + .split()[1][1:-1] except: pass odict = dict @@ -1495,8 +1523,8 @@ dictkeys = dict.keys() else: dictkeys = range(len(dict)) - vlist = self.__formatVariablesList(dictkeys, dict, scope, filter, - formatSequences) + vlist = self.__formatVariablesList( + dictkeys, dict, scope, filter, formatSequences) varlist.extend(vlist) if obj is not None and not formatSequences: @@ -1510,7 +1538,8 @@ except: pass - self.write('%s%s\n' % (DebugProtocol.ResponseVariable, unicode(varlist))) + self.write('%s%s\n' % ( + DebugProtocol.ResponseVariable, unicode(varlist))) def __formatQt4Variable(self, value, vtype): """ @@ -1566,7 +1595,8 @@ h, s, v, a = value.getHsv() varlist.append(("hsv", "int", "%d, %d, %d, %d" % (h, s, v, a))) c, m, y, k, a = value.getCmyk() - varlist.append(("cmyk", "int", "%d, %d, %d, %d, %d" % (c, m, y, k, a))) + varlist.append( + ("cmyk", "int", "%d, %d, %d, %d, %d" % (c, m, y, k, a))) elif qttype == 'QDate': varlist.append(("", "QDate", "%s" % value.toString())) elif qttype == 'QTime': @@ -1575,8 +1605,10 @@ varlist.append(("", "QDateTime", "%s" % value.toString())) elif qttype == 'QDir': varlist.append(("path", "str", "%s" % value.path())) - varlist.append(("absolutePath", "str", "%s" % value.absolutePath())) - varlist.append(("canonicalPath", "str", "%s" % value.canonicalPath())) + varlist.append( + ("absolutePath", "str", "%s" % value.absolutePath())) + varlist.append( + ("canonicalPath", "str", "%s" % value.canonicalPath())) elif qttype == 'QFile': varlist.append(("fileName", "str", "%s" % value.fileName())) elif qttype == 'QFont': @@ -1598,7 +1630,8 @@ if value.isValid(): varlist.append(("row", "int", "%s" % value.row())) varlist.append(("column", "int", "%s" % value.column())) - varlist.append(("internalId", "int", "%s" % value.internalId())) + varlist.append( + ("internalId", "int", "%s" % value.internalId())) varlist.append(("internalPointer", "void *", "%s" % \ value.internalPointer())) elif qttype == 'QRegExp': @@ -1611,7 +1644,8 @@ varlist.append(("icon text", "str", "%s" % value.iconText())) varlist.append(("tooltip", "str", "%s" % value.toolTip())) varlist.append(("whatsthis", "str", "%s" % value.whatsThis())) - varlist.append(("shortcut", "str", "%s" % value.shortcut().toString())) + varlist.append( + ("shortcut", "str", "%s" % value.shortcut().toString())) elif qttype == 'QKeySequence': varlist.append(("value", "", "%s" % value.toString())) @@ -1633,7 +1667,8 @@ # Networking stuff elif qttype == 'QHostAddress': - varlist.append(("address", "QHostAddress", "%s" % value.toString())) + varlist.append( + ("address", "QHostAddress", "%s" % value.toString())) return varlist @@ -1644,24 +1679,25 @@ The dictionary passed in to it is scanned. Variables are only added to the list, if their type is not contained - in the filter list and their name doesn't match any of the filter expressions. - The formated variables list (a list of tuples of 3 values) is returned. + in the filter list and their name doesn't match any of + the filter expressions. The formated variables list (a list of tuples + of 3 values) is returned. @param keylist keys of the dictionary @param dict the dictionary to be scanned @param scope 1 to filter using the globals filter, 0 using the locals filter (int). - Variables are only added to the list, if their name do not match any of the - filter expressions. - @param filter the indices of variable types to be filtered. Variables are - only added to the list, if their type is not contained in the filter - list. - @param formatSequences flag indicating, that sequence or dictionary variables - should be formatted. If it is 0 (or false), just the number of items contained - in these variables is returned. (boolean) - @return A tuple consisting of a list of formatted variables. Each variable - entry is a tuple of three elements, the variable name, its type and - value. + Variables are only added to the list, if their name do not match + any of the filter expressions. + @param filter the indices of variable types to be filtered. Variables + are only added to the list, if their type is not contained in the + filter list. + @param formatSequences flag indicating, that sequence or dictionary + variables should be formatted. If it is 0 (or false), just the + number of items contained in these variables is returned. (boolean) + @return A tuple consisting of a list of formatted variables. Each + variable entry is a tuple of three elements, the variable name, + its type and value. """ varlist = [] if scope: @@ -1703,10 +1739,12 @@ continue except ValueError: if valtype == "classobj": - if ConfigVarTypeStrings.index('instance') in filter: + if ConfigVarTypeStrings.index( + 'instance') in filter: continue elif valtype == "sip.methoddescriptor": - if ConfigVarTypeStrings.index('instance method') in filter: + if ConfigVarTypeStrings.index( + 'instance method') in filter: continue elif valtype == "sip.enumtype": if ConfigVarTypeStrings.index('class') in filter: @@ -1799,9 +1837,12 @@ @param host hostname of the debug server (string) @param port portnumber of the debug server (int) @param enableTrace flag to enable the tracing function (boolean) - @param exceptions flag to enable exception reporting of the IDE (boolean) - @param tracePython flag to enable tracing into the Python library (boolean) - @param redirect flag indicating redirection of stdin, stdout and stderr (boolean) + @param exceptions flag to enable exception reporting of the IDE + (boolean) + @param tracePython flag to enable tracing into the Python library + (boolean) + @param redirect flag indicating redirection of stdin, stdout and + stderr (boolean) """ global debugClient if host is None: @@ -1821,7 +1862,8 @@ if self.running: self.__setCoding(self.running) self.passive = 1 - self.write("%s%s|%d\n" % (DebugProtocol.PassiveStartup, self.running, exceptions)) + self.write("%s%s|%d\n" % ( + DebugProtocol.PassiveStartup, self.running, exceptions)) self.__interact() # setup the debugger variables @@ -1852,9 +1894,12 @@ @param wd working directory for the program execution (string) @param host hostname of the debug server (string) @param port portnumber of the debug server (int) - @param exceptions flag to enable exception reporting of the IDE (boolean) - @param tracePython flag to enable tracing into the Python library (boolean) - @param redirect flag indicating redirection of stdin, stdout and stderr (boolean) + @param exceptions flag to enable exception reporting of the IDE + (boolean) + @param tracePython flag to enable tracing into the Python library + (boolean) + @param redirect flag indicating redirection of stdin, stdout and + stderr (boolean) """ if host is None: host = os.getenv('ERICHOST', 'localhost') @@ -1880,7 +1925,8 @@ self.debugging = 1 self.passive = 1 - self.write("%s%s|%d\n" % (DebugProtocol.PassiveStartup, self.running, exceptions)) + self.write("%s%s|%d\n" % ( + DebugProtocol.PassiveStartup, self.running, exceptions)) self.__interact() self.attachThread(mainThread=1) @@ -1893,8 +1939,8 @@ # This will eventually enter a local event loop. # Note the use of backquotes to cause a repr of self.running. The # need for this is on Windows os where backslash is the path separator. - # They will get inadvertantly stripped away during the eval causing IOErrors - # if self.running is passed as a normal str. + # They will get inadvertantly stripped away during the eval causing + # IOErrors if self.running is passed as a normal str. self.debugMod.__dict__['__file__'] = self.running sys.modules['__main__'] = self.debugMod res = self.mainThread.run('execfile(' + repr(self.running) + ')', @@ -1930,7 +1976,8 @@ family = socket.AF_INET else: family = socket.AF_INET6 - return socket.getaddrinfo(host, None, family, socket.SOCK_STREAM)[0][4][0] + return socket.getaddrinfo(host, None, family, + socket.SOCK_STREAM)[0][4][0] def main(self): """ @@ -1988,7 +2035,8 @@ if not self.noencoding: self.__coding = self.defaultCoding self.startProgInDebugger(args, wd, host, port, - exceptions=exceptions, tracePython=tracePython, + exceptions=exceptions, + tracePython=tracePython, redirect=redirect) else: if sys.argv[1] == '--no-encoding': @@ -2052,7 +2100,8 @@ def close(self, fd): """ - Private method implementing a close method as a replacement for os.close(). + Private method implementing a close method as a replacement for + os.close(). It prevents the debugger connections from being closed. @@ -2072,7 +2121,8 @@ @param firstEntry entry to be put first in sys.path (string) @return path list for use as sys.path (list of strings) """ - sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep) + sysPath = [path for path in os.environ.get("PYTHONPATH", "") + .split(os.pathsep) if path not in sys.path] + sys.path[:] if "" in sysPath: sysPath.remove("")