53 DebugClientOrigRawInput = __main__.__builtins__.__dict__['raw_input'] |
54 DebugClientOrigRawInput = __main__.__builtins__.__dict__['raw_input'] |
54 __main__.__builtins__.__dict__['raw_input'] = DebugClientRawInput |
55 __main__.__builtins__.__dict__['raw_input'] = DebugClientRawInput |
55 |
56 |
56 ################################################################################ |
57 ################################################################################ |
57 |
58 |
|
59 |
58 def DebugClientInput(prompt=""): |
60 def DebugClientInput(prompt=""): |
59 """ |
61 """ |
60 Replacement for the standard input builtin. |
62 Replacement for the standard input builtin. |
61 |
63 |
62 This function works with the split debugger. |
64 This function works with the split debugger. |
77 DebugClientOrigInput = __main__.__builtins__.__dict__['input'] |
79 DebugClientOrigInput = __main__.__builtins__.__dict__['input'] |
78 __main__.__builtins__.__dict__['input'] = DebugClientInput |
80 __main__.__builtins__.__dict__['input'] = DebugClientInput |
79 |
81 |
80 ################################################################################ |
82 ################################################################################ |
81 |
83 |
|
84 |
82 def DebugClientFork(): |
85 def DebugClientFork(): |
83 """ |
86 """ |
84 Replacement for the standard os.fork(). |
87 Replacement for the standard os.fork(). |
85 """ |
88 """ |
86 if DebugClientInstance is None: |
89 if DebugClientInstance is None: |
111 DebugClientOrigClose = os.close |
115 DebugClientOrigClose = os.close |
112 os.close = DebugClientClose |
116 os.close = DebugClientClose |
113 |
117 |
114 ################################################################################ |
118 ################################################################################ |
115 |
119 |
|
120 |
116 def DebugClientSetRecursionLimit(limit): |
121 def DebugClientSetRecursionLimit(limit): |
117 """ |
122 """ |
118 Replacement for the standard sys.setrecursionlimit(limit). |
123 Replacement for the standard sys.setrecursionlimit(limit). |
119 |
124 |
120 @param limit recursion limit (integer) |
125 @param limit recursion limit (integer) |
129 sys.setrecursionlimit = DebugClientSetRecursionLimit |
134 sys.setrecursionlimit = DebugClientSetRecursionLimit |
130 DebugClientSetRecursionLimit(sys.getrecursionlimit()) |
135 DebugClientSetRecursionLimit(sys.getrecursionlimit()) |
131 |
136 |
132 ################################################################################ |
137 ################################################################################ |
133 |
138 |
|
139 |
134 class DebugClientBase(object): |
140 class DebugClientBase(object): |
135 """ |
141 """ |
136 Class implementing the client side of the debugger. |
142 Class implementing the client side of the debugger. |
137 |
143 |
138 It provides access to the Python interpeter from a debugger running in another |
144 It provides access to the Python interpeter from a debugger running in another |
143 statements. Commands and statement are always exactly one line and may be |
149 statements. Commands and statement are always exactly one line and may be |
144 interspersed. |
150 interspersed. |
145 |
151 |
146 The protocol is as follows. First the client opens a connection to the |
152 The protocol is as follows. First the client opens a connection to the |
147 debugger and then sends a series of one line commands. A command is either |
153 debugger and then sends a series of one line commands. A command is either |
148 >Load<, >Step<, >StepInto<, ... or a Python statement. |
154 >Load<, >Step<, >StepInto<, ... or a Python statement. |
149 See DebugProtocol.py for a listing of valid protocol tokens. |
155 See DebugProtocol.py for a listing of valid protocol tokens. |
150 |
156 |
151 A Python statement consists of the statement to execute, followed (in a |
157 A Python statement consists of the statement to execute, followed (in a |
152 separate line) by >OK?<. If the statement was incomplete then the response |
158 separate line) by >OK?<. If the statement was incomplete then the response |
153 is >Continue<. If there was an exception then the response is |
159 is >Continue<. If there was an exception then the response is |
154 >Exception<. |
160 >Exception<. |
155 Otherwise the response is >OK<. The reason for the >OK?< part is to |
161 Otherwise the response is >OK<. The reason for the >OK?< part is to |
156 provide a sentinal (ie. the responding >OK<) after any possible output as a |
162 provide a sentinal (ie. the responding >OK<) after any possible output as a |
157 result of executing the command. |
163 result of executing the command. |
158 |
164 |
269 if m: |
275 if m: |
270 self.__coding = m.group(1) |
276 self.__coding = m.group(1) |
271 return |
277 return |
272 self.__coding = default |
278 self.__coding = default |
273 |
279 |
274 def attachThread(self, target = None, args = None, kwargs = None, mainThread = 0): |
280 def attachThread(self, target=None, args=None, kwargs=None, mainThread=0): |
275 """ |
281 """ |
276 Public method to setup a thread for DebugClient to debug. |
282 Public method to setup a thread for DebugClient to debug. |
277 |
283 |
278 If mainThread is non-zero, then we are attaching to the already |
284 If mainThread is non-zero, then we are attaching to the already |
279 started mainthread of the app and the rest of the args are ignored. |
285 started mainthread of the app and the rest of the args are ignored. |
280 |
286 |
281 This is just an empty function and is overridden in the threaded |
287 This is just an empty function and is overridden in the threaded |
282 debugger. |
288 debugger. |
283 |
289 |
284 @param target the start function of the target thread (i.e. the user code) |
290 @param target the start function of the target thread (i.e. the user code) |
285 @param args arguments to pass to target |
291 @param args arguments to pass to target |
286 @param kwargs keyword arguments to pass to target |
292 @param kwargs keyword arguments to pass to target |
287 @param mainThread non-zero, if we are attaching to the already |
293 @param mainThread non-zero, if we are attaching to the already |
288 started mainthread of the app |
294 started mainthread of the app |
289 @return The identifier of the created thread |
295 @return The identifier of the created thread |
290 """ |
296 """ |
291 if self.debugging: |
297 if self.debugging: |
292 sys.setprofile(self.profile) |
298 sys.setprofile(self.profile) |
312 d["broken"] = self.isBroken() |
318 d["broken"] = self.isBroken() |
313 threadList.append(d) |
319 threadList.append(d) |
314 |
320 |
315 self.write('%s%s\n' % (ResponseThreadList, unicode((currentId, threadList)))) |
321 self.write('%s%s\n' % (ResponseThreadList, unicode((currentId, threadList)))) |
316 |
322 |
317 def raw_input(self,prompt,echo): |
323 def raw_input(self, prompt, echo): |
318 """ |
324 """ |
319 Public method to implement raw_input() using the event loop. |
325 Public method to implement raw_input() using the event loop. |
320 |
326 |
321 @param prompt the prompt to be shown (string) |
327 @param prompt the prompt to be shown (string) |
322 @param echo Flag indicating echoing of the input (boolean) |
328 @param echo Flag indicating echoing of the input (boolean) |
325 self.write("%s%s\n" % (ResponseRaw, unicode((prompt, echo)))) |
331 self.write("%s%s\n" % (ResponseRaw, unicode((prompt, echo)))) |
326 self.inRawMode = 1 |
332 self.inRawMode = 1 |
327 self.eventLoop(True) |
333 self.eventLoop(True) |
328 return self.rawLine |
334 return self.rawLine |
329 |
335 |
330 def input(self,prompt): |
336 def input(self, prompt): |
331 """ |
337 """ |
332 Public method to implement input() using the event loop. |
338 Public method to implement input() using the event loop. |
333 |
339 |
334 @param prompt the prompt to be shown (string) |
340 @param prompt the prompt to be shown (string) |
335 @return the entered string evaluated as a Python expresion |
341 @return the entered string evaluated as a Python expresion |
451 |
457 |
452 if cmd == RequestEnv: |
458 if cmd == RequestEnv: |
453 env = eval(arg) |
459 env = eval(arg) |
454 for key, value in env.items(): |
460 for key, value in env.items(): |
455 if key.endswith("+"): |
461 if key.endswith("+"): |
456 if os.environ.has_key(key[:-1]): |
462 if key[:-1] in os.environ: |
457 os.environ[key[:-1]] += value |
463 os.environ[key[:-1]] += value |
458 else: |
464 else: |
459 os.environ[key[:-1]] = value |
465 os.environ[key[:-1]] = value |
460 else: |
466 else: |
461 os.environ[key] = value |
467 os.environ[key] = value |
493 self.mainThread.tracePython = tracePython |
499 self.mainThread.tracePython = tracePython |
494 |
500 |
495 # This will eventually enter a local event loop. |
501 # This will eventually enter a local event loop. |
496 # Note the use of backquotes to cause a repr of self.running. The |
502 # Note the use of backquotes to cause a repr of self.running. The |
497 # need for this is on Windows os where backslash is the path separator. |
503 # need for this is on Windows os where backslash is the path separator. |
498 # They will get inadvertantly stripped away during the eval causing |
504 # They will get inadvertantly stripped away during the eval causing |
499 # IOErrors, if self.running is passed as a normal str. |
505 # IOErrors, if self.running is passed as a normal str. |
500 self.debugMod.__dict__['__file__'] = self.running |
506 self.debugMod.__dict__['__file__'] = self.running |
501 sys.modules['__main__'] = self.debugMod |
507 sys.modules['__main__'] = self.debugMod |
502 res = self.mainThread.run('execfile(' + `self.running` + ')', |
508 res = self.mainThread.run('execfile(' + repr(self.running) + ')', |
503 self.debugMod.__dict__) |
509 self.debugMod.__dict__) |
504 self.progTerminated(res) |
510 self.progTerminated(res) |
505 return |
511 return |
506 |
512 |
507 if cmd == RequestRun: |
513 if cmd == RequestRun: |
552 # set the system exception handling function to ensure, that |
558 # set the system exception handling function to ensure, that |
553 # we report on all unhandled exceptions |
559 # we report on all unhandled exceptions |
554 sys.excepthook = self.__unhandled_exception |
560 sys.excepthook = self.__unhandled_exception |
555 |
561 |
556 # generate a coverage object |
562 # generate a coverage object |
557 self.cover = coverage(auto_data = True, |
563 self.cover = coverage(auto_data=True, |
558 data_file = "%s.coverage" % os.path.splitext(sys.argv[0])[0]) |
564 data_file="%s.coverage" % os.path.splitext(sys.argv[0])[0]) |
559 self.cover.use_cache(True) |
565 self.cover.use_cache(True) |
560 |
566 |
561 if int(erase): |
567 if int(erase): |
562 self.cover.erase() |
568 self.cover.erase() |
563 sys.modules['__main__'] = self.debugMod |
569 sys.modules['__main__'] = self.debugMod |
751 self.write(ResponseException + '\n') |
757 self.write(ResponseException + '\n') |
752 |
758 |
753 return |
759 return |
754 |
760 |
755 if cmd == RequestBanner: |
761 if cmd == RequestBanner: |
756 self.write('%s%s\n' % (ResponseBanner, |
762 self.write('%s%s\n' % (ResponseBanner, |
757 unicode(("Python %s" % sys.version, socket.gethostname(), |
763 unicode(("Python %s" % sys.version, socket.gethostname(), |
758 self.variant)))) |
764 self.variant)))) |
759 return |
765 return |
760 |
766 |
761 if cmd == RequestCapabilities: |
767 if cmd == RequestCapabilities: |
762 self.write('%s%d, "Python"\n' % (ResponseCapabilities, |
768 self.write('%s%d, "Python"\n' % (ResponseCapabilities, |
763 self.__clientCapabilities())) |
769 self.__clientCapabilities())) |
764 return |
770 return |
765 |
771 |
766 if cmd == RequestCompletion: |
772 if cmd == RequestCompletion: |
767 self.__completionList(arg) |
773 self.__completionList(arg) |
854 try: |
860 try: |
855 code = self.compile_command(self.buffer, self.readstream.name) |
861 code = self.compile_command(self.buffer, self.readstream.name) |
856 except (OverflowError, SyntaxError, ValueError): |
862 except (OverflowError, SyntaxError, ValueError): |
857 # Report the exception |
863 # Report the exception |
858 sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() |
864 sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info() |
859 map(self.write,traceback.format_exception_only(sys.last_type,sys.last_value)) |
865 map(self.write, traceback.format_exception_only(sys.last_type, sys.last_value)) |
860 self.buffer = '' |
866 self.buffer = '' |
861 |
867 |
862 self.__exceptionRaised() |
868 self.__exceptionRaised() |
863 else: |
869 else: |
864 if code is None: |
870 if code is None: |
888 cf = cf.f_back |
894 cf = cf.f_back |
889 frmnr -= 1 |
895 frmnr -= 1 |
890 _globals = cf.f_globals |
896 _globals = cf.f_globals |
891 _locals = self.currentThread.getCurrentFrameLocals() |
897 _locals = self.currentThread.getCurrentFrameLocals() |
892 # reset sys.stdout to our redirector (unconditionally) |
898 # reset sys.stdout to our redirector (unconditionally) |
893 if _globals.has_key("sys"): |
899 if "sys" in _globals: |
894 __stdout = _globals["sys"].stdout |
900 __stdout = _globals["sys"].stdout |
895 _globals["sys"].stdout = self.writestream |
901 _globals["sys"].stdout = self.writestream |
896 exec code in _globals, _locals |
902 exec code in _globals, _locals |
897 _globals["sys"].stdout = __stdout |
903 _globals["sys"].stdout = __stdout |
898 elif _locals.has_key("sys"): |
904 elif "sys" in _locals: |
899 __stdout = _locals["sys"].stdout |
905 __stdout = _locals["sys"].stdout |
900 _locals["sys"].stdout = self.writestream |
906 _locals["sys"].stdout = self.writestream |
901 exec code in _globals, _locals |
907 exec code in _globals, _locals |
902 _locals["sys"].stdout = __stdout |
908 _locals["sys"].stdout = __stdout |
903 else: |
909 else: |
954 """ |
960 """ |
955 Private method to Interact with the debugger. |
961 Private method to Interact with the debugger. |
956 """ |
962 """ |
957 global DebugClientInstance |
963 global DebugClientInstance |
958 |
964 |
959 self.setDescriptors(self.readstream,self.writestream) |
965 self.setDescriptors(self.readstream, self.writestream) |
960 DebugClientInstance = self |
966 DebugClientInstance = self |
961 |
967 |
962 if not self.passive: |
968 if not self.passive: |
963 # At this point simulate an event loop. |
969 # At this point simulate an event loop. |
964 self.eventLoop() |
970 self.eventLoop() |
965 |
971 |
966 def eventLoop(self, disablePolling = False): |
972 def eventLoop(self, disablePolling=False): |
967 """ |
973 """ |
968 Public method implementing our event loop. |
974 Public method implementing our event loop. |
969 |
975 |
970 @param disablePolling flag indicating to enter an event loop with |
976 @param disablePolling flag indicating to enter an event loop with |
971 polling disabled (boolean) |
977 polling disabled (boolean) |
981 |
987 |
982 if AsyncPendingWrite(self.errorstream): |
988 if AsyncPendingWrite(self.errorstream): |
983 wrdy.append(self.errorstream) |
989 wrdy.append(self.errorstream) |
984 |
990 |
985 try: |
991 try: |
986 rrdy, wrdy, xrdy = select.select([self.readstream],wrdy,[]) |
992 rrdy, wrdy, xrdy = select.select([self.readstream], wrdy, []) |
987 except (select.error, KeyboardInterrupt, socket.error): |
993 except (select.error, KeyboardInterrupt, socket.error): |
988 # just carry on |
994 # just carry on |
989 continue |
995 continue |
990 |
996 |
991 if self.readstream in rrdy: |
997 if self.readstream in rrdy: |
1023 if AsyncPendingWrite(self.errorstream): |
1029 if AsyncPendingWrite(self.errorstream): |
1024 wrdy.append(self.errorstream) |
1030 wrdy.append(self.errorstream) |
1025 |
1031 |
1026 # immediate return if nothing is ready. |
1032 # immediate return if nothing is ready. |
1027 try: |
1033 try: |
1028 rrdy, wrdy, xrdy = select.select([self.readstream],wrdy,[],0) |
1034 rrdy, wrdy, xrdy = select.select([self.readstream], wrdy, [], 0) |
1029 except (select.error, KeyboardInterrupt, socket.error): |
1035 except (select.error, KeyboardInterrupt, socket.error): |
1030 return |
1036 return |
1031 |
1037 |
1032 if self.readstream in rrdy: |
1038 if self.readstream in rrdy: |
1033 self.readReady(self.readstream.fileno()) |
1039 self.readReady(self.readstream.fileno()) |
1036 self.writeReady(self.writestream.fileno()) |
1042 self.writeReady(self.writestream.fileno()) |
1037 |
1043 |
1038 if self.errorstream in wrdy: |
1044 if self.errorstream in wrdy: |
1039 self.writeReady(self.errorstream.fileno()) |
1045 self.writeReady(self.errorstream.fileno()) |
1040 |
1046 |
1041 def connectDebugger(self,port,remoteAddress=None,redirect=1): |
1047 def connectDebugger(self, port, remoteAddress=None, redirect=1): |
1042 """ |
1048 """ |
1043 Public method to establish a session with the debugger. |
1049 Public method to establish a session with the debugger. |
1044 |
1050 |
1045 It opens a network connection to the debugger, connects it to stdin, |
1051 It opens a network connection to the debugger, connects it to stdin, |
1046 stdout and stderr and saves these file objects in case the application |
1052 stdout and stderr and saves these file objects in case the application |
1047 being debugged redirects them itself. |
1053 being debugged redirects them itself. |
1048 |
1054 |
1049 @param port the port number to connect to (int) |
1055 @param port the port number to connect to (int) |
1050 @param remoteAddress the network address of the debug server host (string) |
1056 @param remoteAddress the network address of the debug server host (string) |
1069 sys.stdout = self.writestream |
1075 sys.stdout = self.writestream |
1070 sys.stderr = self.errorstream |
1076 sys.stderr = self.errorstream |
1071 self.redirect = redirect |
1077 self.redirect = redirect |
1072 |
1078 |
1073 # attach to the main thread here |
1079 # attach to the main thread here |
1074 self.attachThread(mainThread = 1) |
1080 self.attachThread(mainThread=1) |
1075 |
1081 |
1076 def __unhandled_exception(self, exctype, excval, exctb): |
1082 def __unhandled_exception(self, exctype, excval, exctb): |
1077 """ |
1083 """ |
1078 Private method called to report an uncaught exception. |
1084 Private method called to report an uncaught exception. |
1079 |
1085 |
1080 @param exctype the type of the exception |
1086 @param exctype the type of the exception |
1081 @param excval data about the exception |
1087 @param excval data about the exception |
1082 @param exctb traceback for the exception |
1088 @param exctb traceback for the exception |
1083 """ |
1089 """ |
1084 self.mainThread.user_exception(None, (exctype,excval,exctb), 1) |
1090 self.mainThread.user_exception(None, (exctype, excval, exctb), 1) |
1085 |
1091 |
1086 def absPath(self,fn): |
1092 def absPath(self, fn): |
1087 """ |
1093 """ |
1088 Public method to convert a filename to an absolute name. |
1094 Public method to convert a filename to an absolute name. |
1089 |
1095 |
1090 sys.path is used as a set of possible prefixes. The name stays |
1096 sys.path is used as a set of possible prefixes. The name stays |
1091 relative if a file could not be found. |
1097 relative if a file could not be found. |
1092 |
1098 |
1093 @param fn filename (string) |
1099 @param fn filename (string) |
1094 @return the converted filename (string) |
1100 @return the converted filename (string) |
1095 """ |
1101 """ |
1096 if os.path.isabs(fn): |
1102 if os.path.isabs(fn): |
1097 return fn |
1103 return fn |
1098 |
1104 |
1099 # Check the cache. |
1105 # Check the cache. |
1100 if self.fncache.has_key(fn): |
1106 if fn in self.fncache: |
1101 return self.fncache[fn] |
1107 return self.fncache[fn] |
1102 |
1108 |
1103 # Search sys.path. |
1109 # Search sys.path. |
1104 for p in sys.path: |
1110 for p in sys.path: |
1105 afn = os.path.abspath(os.path.join(p,fn)) |
1111 afn = os.path.abspath(os.path.join(p, fn)) |
1106 afn = os.path.normcase(afn) |
1112 afn = os.path.normcase(afn) |
1107 |
1113 |
1108 if os.path.exists(afn): |
1114 if os.path.exists(afn): |
1109 self.fncache[fn] = afn |
1115 self.fncache[fn] = afn |
1110 d = os.path.dirname(afn) |
1116 d = os.path.dirname(afn) |
1112 self.dircache.append(d) |
1118 self.dircache.append(d) |
1113 return afn |
1119 return afn |
1114 |
1120 |
1115 # Search the additional directory cache |
1121 # Search the additional directory cache |
1116 for p in self.dircache: |
1122 for p in self.dircache: |
1117 afn = os.path.abspath(os.path.join(p,fn)) |
1123 afn = os.path.abspath(os.path.join(p, fn)) |
1118 afn = os.path.normcase(afn) |
1124 afn = os.path.normcase(afn) |
1119 |
1125 |
1120 if os.path.exists(afn): |
1126 if os.path.exists(afn): |
1121 self.fncache[fn] = afn |
1127 self.fncache[fn] = afn |
1122 return afn |
1128 return afn |
1252 if len(dict): |
1258 if len(dict): |
1253 udict = dict |
1259 udict = dict |
1254 ndict = {} |
1260 ndict = {} |
1255 # this has to be in line with VariablesViewer.indicators |
1261 # this has to be in line with VariablesViewer.indicators |
1256 if var[i][-2:] in ["[]", "()", "{}"]: |
1262 if var[i][-2:] in ["[]", "()", "{}"]: |
1257 if i+1 == len(var): |
1263 if i + 1 == len(var): |
1258 if var[i][:-2] == '...': |
1264 if var[i][:-2] == '...': |
1259 dictkeys = [var[i-1]] |
1265 dictkeys = [var[i - 1]] |
1260 else: |
1266 else: |
1261 dictkeys = [var[i][:-2]] |
1267 dictkeys = [var[i][:-2]] |
1262 formatSequences = 1 |
1268 formatSequences = 1 |
1263 if not access and not oaccess: |
1269 if not access and not oaccess: |
1264 if var[i][:-2] == '...': |
1270 if var[i][:-2] == '...': |
1265 access = '["%s"]' % var[i-1] |
1271 access = '["%s"]' % var[i - 1] |
1266 dict = odict |
1272 dict = odict |
1267 else: |
1273 else: |
1268 access = '["%s"]' % var[i][:-2] |
1274 access = '["%s"]' % var[i][:-2] |
1269 else: |
1275 else: |
1270 if var[i][:-2] == '...': |
1276 if var[i][:-2] == '...': |
1271 if oaccess: |
1277 if oaccess: |
1272 access = oaccess |
1278 access = oaccess |
1273 else: |
1279 else: |
1274 access = '%s[%s]' % (access, var[i-1]) |
1280 access = '%s[%s]' % (access, var[i - 1]) |
1275 dict = odict |
1281 dict = odict |
1276 else: |
1282 else: |
1277 if oaccess: |
1283 if oaccess: |
1278 access = '%s[%s]' % (oaccess, var[i][:-2]) |
1284 access = '%s[%s]' % (oaccess, var[i][:-2]) |
1279 oaccess = '' |
1285 oaccess = '' |
1283 isDict = 1 |
1289 isDict = 1 |
1284 break |
1290 break |
1285 else: |
1291 else: |
1286 if not access: |
1292 if not access: |
1287 if var[i][:-2] == '...': |
1293 if var[i][:-2] == '...': |
1288 access = '["%s"]' % var[i-1] |
1294 access = '["%s"]' % var[i - 1] |
1289 dict = odict |
1295 dict = odict |
1290 else: |
1296 else: |
1291 access = '["%s"]' % var[i][:-2] |
1297 access = '["%s"]' % var[i][:-2] |
1292 else: |
1298 else: |
1293 if var[i][:-2] == '...': |
1299 if var[i][:-2] == '...': |
1294 access = '%s[%s]' % (access, var[i-1]) |
1300 access = '%s[%s]' % (access, var[i - 1]) |
1295 dict = odict |
1301 dict = odict |
1296 else: |
1302 else: |
1297 if oaccess: |
1303 if oaccess: |
1298 access = '%s[%s]' % (oaccess, var[i][:-2]) |
1304 access = '%s[%s]' % (oaccess, var[i][:-2]) |
1299 oaccess = '' |
1305 oaccess = '' |
1380 dict = dict[dictkeys[0]] |
1386 dict = dict[dictkeys[0]] |
1381 if isDict: |
1387 if isDict: |
1382 dictkeys = dict.keys() |
1388 dictkeys = dict.keys() |
1383 else: |
1389 else: |
1384 dictkeys = range(len(dict)) |
1390 dictkeys = range(len(dict)) |
1385 vlist = self.__formatVariablesList(dictkeys, dict, scope, filter, |
1391 vlist = self.__formatVariablesList(dictkeys, dict, scope, filter, |
1386 formatSequences) |
1392 formatSequences) |
1387 varlist.extend(vlist) |
1393 varlist.extend(vlist) |
1388 |
1394 |
1389 if obj is not None and not formatSequences: |
1395 if obj is not None and not formatSequences: |
1390 if unicode(repr(obj)).startswith('{'): |
1396 if unicode(repr(obj)).startswith('{'): |
1400 """ |
1406 """ |
1401 Private method to produce a formated output of a simple Qt4 type. |
1407 Private method to produce a formated output of a simple Qt4 type. |
1402 |
1408 |
1403 @param value variable to be formated |
1409 @param value variable to be formated |
1404 @param vtype type of the variable to be formatted (string) |
1410 @param vtype type of the variable to be formatted (string) |
1405 @return A tuple consisting of a list of formatted variables. Each |
1411 @return A tuple consisting of a list of formatted variables. Each |
1406 variable entry is a tuple of three elements, the variable name, |
1412 variable entry is a tuple of three elements, the variable name, |
1407 its type and value. |
1413 its type and value. |
1408 """ |
1414 """ |
1409 qttype = vtype.split('.')[-1] |
1415 qttype = vtype.split('.')[-1] |
1410 varlist = [] |
1416 varlist = [] |
1411 if qttype == 'QChar': |
1417 if qttype == 'QChar': |
1509 elif qttype == 'QHostAddress': |
1515 elif qttype == 'QHostAddress': |
1510 varlist.append(("address", "QHostAddress", "%s" % value.toString())) |
1516 varlist.append(("address", "QHostAddress", "%s" % value.toString())) |
1511 |
1517 |
1512 return varlist |
1518 return varlist |
1513 |
1519 |
1514 def __formatVariablesList(self, keylist, dict, scope, filter = [], |
1520 def __formatVariablesList(self, keylist, dict, scope, filter=[], |
1515 formatSequences = 0): |
1521 formatSequences=0): |
1516 """ |
1522 """ |
1517 Private method to produce a formated variables list. |
1523 Private method to produce a formated variables list. |
1518 |
1524 |
1519 The dictionary passed in to it is scanned. Variables are |
1525 The dictionary passed in to it is scanned. Variables are |
1520 only added to the list, if their type is not contained |
1526 only added to the list, if their type is not contained |
1521 in the filter list and their name doesn't match any of the filter expressions. |
1527 in the filter list and their name doesn't match any of the filter expressions. |
1522 The formated variables list (a list of tuples of 3 values) is returned. |
1528 The formated variables list (a list of tuples of 3 values) is returned. |
1523 |
1529 |
1524 @param keylist keys of the dictionary |
1530 @param keylist keys of the dictionary |
1525 @param dict the dictionary to be scanned |
1531 @param dict the dictionary to be scanned |
1526 @param scope 1 to filter using the globals filter, 0 using the locals |
1532 @param scope 1 to filter using the globals filter, 0 using the locals |
1527 filter (int). |
1533 filter (int). |
1528 Variables are only added to the list, if their name do not match any of the |
1534 Variables are only added to the list, if their name do not match any of the |
1529 filter expressions. |
1535 filter expressions. |
1530 @param filter the indices of variable types to be filtered. Variables are |
1536 @param filter the indices of variable types to be filtered. Variables are |
1531 only added to the list, if their type is not contained in the filter |
1537 only added to the list, if their type is not contained in the filter |
1532 list. |
1538 list. |
1533 @param formatSequences flag indicating, that sequence or dictionary variables |
1539 @param formatSequences flag indicating, that sequence or dictionary variables |
1534 should be formatted. If it is 0 (or false), just the number of items contained |
1540 should be formatted. If it is 0 (or false), just the number of items contained |
1535 in these variables is returned. (boolean) |
1541 in these variables is returned. (boolean) |
1536 @return A tuple consisting of a list of formatted variables. Each variable |
1542 @return A tuple consisting of a list of formatted variables. Each variable |
1537 entry is a tuple of three elements, the variable name, its type and |
1543 entry is a tuple of three elements, the variable name, its type and |
1538 value. |
1544 value. |
1539 """ |
1545 """ |
1540 varlist = [] |
1546 varlist = [] |
1541 if scope: |
1547 if scope: |
1542 patternFilterObjects = self.globalsFilterObjects |
1548 patternFilterObjects = self.globalsFilterObjects |
1607 |
1613 |
1608 def __generateFilterObjects(self, scope, filterString): |
1614 def __generateFilterObjects(self, scope, filterString): |
1609 """ |
1615 """ |
1610 Private slot to convert a filter string to a list of filter objects. |
1616 Private slot to convert a filter string to a list of filter objects. |
1611 |
1617 |
1612 @param scope 1 to generate filter for global variables, 0 for local |
1618 @param scope 1 to generate filter for global variables, 0 for local |
1613 variables (int) |
1619 variables (int) |
1614 @param filterString string of filter patterns separated by ';' |
1620 @param filterString string of filter patterns separated by ';' |
1615 """ |
1621 """ |
1616 patternFilterObjects = [] |
1622 patternFilterObjects = [] |
1617 for pattern in filterString.split(';'): |
1623 for pattern in filterString.split(';'): |
1654 except: |
1660 except: |
1655 comp = None |
1661 comp = None |
1656 |
1662 |
1657 self.write("%s%s||%s\n" % (ResponseCompletion, unicode(completions), text)) |
1663 self.write("%s%s||%s\n" % (ResponseCompletion, unicode(completions), text)) |
1658 |
1664 |
1659 def startDebugger(self, filename = None, host = None, port = None, |
1665 def startDebugger(self, filename=None, host=None, port=None, |
1660 enableTrace = 1, exceptions = 1, tracePython = 0, redirect = 1): |
1666 enableTrace=1, exceptions=1, tracePython=0, redirect=1): |
1661 """ |
1667 """ |
1662 Public method used to start the remote debugger. |
1668 Public method used to start the remote debugger. |
1663 |
1669 |
1664 @param filename the program to be debugged (string) |
1670 @param filename the program to be debugged (string) |
1665 @param host hostname of the debug server (string) |
1671 @param host hostname of the debug server (string) |
1695 self.dircache = [] |
1701 self.dircache = [] |
1696 self.mainFrame = None |
1702 self.mainFrame = None |
1697 self.inRawMode = 0 |
1703 self.inRawMode = 0 |
1698 self.debugging = 1 |
1704 self.debugging = 1 |
1699 |
1705 |
1700 self.attachThread(mainThread = 1) |
1706 self.attachThread(mainThread=1) |
1701 self.mainThread.tracePython = tracePython |
1707 self.mainThread.tracePython = tracePython |
1702 |
1708 |
1703 # set the system exception handling function to ensure, that |
1709 # set the system exception handling function to ensure, that |
1704 # we report on all unhandled exceptions |
1710 # we report on all unhandled exceptions |
1705 sys.excepthook = self.__unhandled_exception |
1711 sys.excepthook = self.__unhandled_exception |
1706 |
1712 |
1707 # now start debugging |
1713 # now start debugging |
1708 if enableTrace: |
1714 if enableTrace: |
1709 self.mainThread.set_trace() |
1715 self.mainThread.set_trace() |
1710 |
1716 |
1711 def startProgInDebugger(self, progargs, wd = '', host = None, |
1717 def startProgInDebugger(self, progargs, wd='', host=None, |
1712 port = None, exceptions = 1, tracePython = 0, redirect = 1): |
1718 port=None, exceptions=1, tracePython=0, redirect=1): |
1713 """ |
1719 """ |
1714 Public method used to start the remote debugger. |
1720 Public method used to start the remote debugger. |
1715 |
1721 |
1716 @param progargs commandline for the program to be debugged |
1722 @param progargs commandline for the program to be debugged |
1717 (list of strings) |
1723 (list of strings) |
1718 @param wd working directory for the program execution (string) |
1724 @param wd working directory for the program execution (string) |
1719 @param host hostname of the debug server (string) |
1725 @param host hostname of the debug server (string) |
1720 @param port portnumber of the debug server (int) |
1726 @param port portnumber of the debug server (int) |
1721 @param exceptions flag to enable exception reporting of the IDE (boolean) |
1727 @param exceptions flag to enable exception reporting of the IDE (boolean) |
1747 |
1753 |
1748 self.passive = 1 |
1754 self.passive = 1 |
1749 self.write("%s%s|%d\n" % (PassiveStartup, self.running, exceptions)) |
1755 self.write("%s%s|%d\n" % (PassiveStartup, self.running, exceptions)) |
1750 self.__interact() |
1756 self.__interact() |
1751 |
1757 |
1752 self.attachThread(mainThread = 1) |
1758 self.attachThread(mainThread=1) |
1753 self.mainThread.tracePython = tracePython |
1759 self.mainThread.tracePython = tracePython |
1754 |
1760 |
1755 # set the system exception handling function to ensure, that |
1761 # set the system exception handling function to ensure, that |
1756 # we report on all unhandled exceptions |
1762 # we report on all unhandled exceptions |
1757 sys.excepthook = self.__unhandled_exception |
1763 sys.excepthook = self.__unhandled_exception |
1761 # need for this is on Windows os where backslash is the path separator. |
1767 # need for this is on Windows os where backslash is the path separator. |
1762 # They will get inadvertantly stripped away during the eval causing IOErrors |
1768 # They will get inadvertantly stripped away during the eval causing IOErrors |
1763 # if self.running is passed as a normal str. |
1769 # if self.running is passed as a normal str. |
1764 self.debugMod.__dict__['__file__'] = self.running |
1770 self.debugMod.__dict__['__file__'] = self.running |
1765 sys.modules['__main__'] = self.debugMod |
1771 sys.modules['__main__'] = self.debugMod |
1766 res = self.mainThread.run('execfile(' + `self.running` + ')', |
1772 res = self.mainThread.run('execfile(' + repr(self.running) + ')', |
1767 self.debugMod.__dict__) |
1773 self.debugMod.__dict__) |
1768 self.progTerminated(res) |
1774 self.progTerminated(res) |
1769 |
1775 |
1770 def run_call(self, scriptname, func, *args): |
1776 def run_call(self, scriptname, func, *args): |
1771 """ |
1777 """ |
1774 @param scriptname name of the script to be debugged (string) |
1780 @param scriptname name of the script to be debugged (string) |
1775 @param func function to be called |
1781 @param func function to be called |
1776 @param *args arguments being passed to func |
1782 @param *args arguments being passed to func |
1777 @return result of the function call |
1783 @return result of the function call |
1778 """ |
1784 """ |
1779 self.startDebugger(scriptname, enableTrace = 0) |
1785 self.startDebugger(scriptname, enableTrace=0) |
1780 res = self.mainThread.runcall(func, *args) |
1786 res = self.mainThread.runcall(func, *args) |
1781 self.progTerminated(res) |
1787 self.progTerminated(res) |
1782 return res |
1788 return res |
1783 |
1789 |
1784 def __resolveHost(self, host): |
1790 def __resolveHost(self, host): |
1843 if not args: |
1849 if not args: |
1844 print "No program given. Aborting!" |
1850 print "No program given. Aborting!" |
1845 else: |
1851 else: |
1846 if not self.noencoding: |
1852 if not self.noencoding: |
1847 self.__coding = self.defaultCoding |
1853 self.__coding = self.defaultCoding |
1848 self.startProgInDebugger(args, wd, host, port, |
1854 self.startProgInDebugger(args, wd, host, port, |
1849 exceptions=exceptions, tracePython=tracePython, |
1855 exceptions=exceptions, tracePython=tracePython, |
1850 redirect=redirect) |
1856 redirect=redirect) |
1851 else: |
1857 else: |
1852 if sys.argv[1] == '--no-encoding': |
1858 if sys.argv[1] == '--no-encoding': |
1853 self.noencoding = True |
1859 self.noencoding = True |
1911 |
1917 |
1912 It prevents the debugger connections from being closed. |
1918 It prevents the debugger connections from being closed. |
1913 |
1919 |
1914 @param fd file descriptor to be closed (integer) |
1920 @param fd file descriptor to be closed (integer) |
1915 """ |
1921 """ |
1916 if fd in [self.readstream.fileno(), self.writestream.fileno(), |
1922 if fd in [self.readstream.fileno(), self.writestream.fileno(), |
1917 self.errorstream.fileno()]: |
1923 self.errorstream.fileno()]: |
1918 return |
1924 return |
1919 |
1925 |
1920 DebugClientOrigClose(fd) |
1926 DebugClientOrigClose(fd) |
1921 |
1927 |
1922 def __getSysPath(self, firstEntry): |
1928 def __getSysPath(self, firstEntry): |
1923 """ |
1929 """ |
1924 Private slot to calculate a path list including the PYTHONPATH |
1930 Private slot to calculate a path list including the PYTHONPATH |
1925 environment variable. |
1931 environment variable. |
1926 |
1932 |
1927 @param firstEntry entry to be put first in sys.path (string) |
1933 @param firstEntry entry to be put first in sys.path (string) |
1928 @return path list for use as sys.path (list of strings) |
1934 @return path list for use as sys.path (list of strings) |
1929 """ |
1935 """ |
1930 sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep) |
1936 sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep) |
1931 if path not in sys.path] + sys.path[:] |
1937 if path not in sys.path] + sys.path[:] |
1932 if "" in sysPath: |
1938 if "" in sysPath: |
1933 sysPath.remove("") |
1939 sysPath.remove("") |
1934 sysPath.insert(0, firstEntry) |
1940 sysPath.insert(0, firstEntry) |
1935 sysPath.insert(0, '') |
1941 sysPath.insert(0, '') |