DebugClients/Python/DebugClientBase.py

changeset 945
8cd4d08fa9f6
parent 935
bf9ee1e00bc5
child 1029
0fb3d1d26eab
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
27 27
28 28
29 DebugClientInstance = None 29 DebugClientInstance = None
30 30
31 ################################################################################ 31 ################################################################################
32
32 33
33 def DebugClientRawInput(prompt="", echo=1): 34 def DebugClientRawInput(prompt="", echo=1):
34 """ 35 """
35 Replacement for the standard raw_input builtin. 36 Replacement for the standard raw_input builtin.
36 37
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:
92 if 'fork' in dir(os): 95 if 'fork' in dir(os):
93 DebugClientOrigFork = os.fork 96 DebugClientOrigFork = os.fork
94 os.fork = DebugClientFork 97 os.fork = DebugClientFork
95 98
96 ################################################################################ 99 ################################################################################
100
97 101
98 def DebugClientClose(fd): 102 def DebugClientClose(fd):
99 """ 103 """
100 Replacement for the standard os.close(fd). 104 Replacement for the standard os.close(fd).
101 105
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
342 348
343 It ensures that the debug server is informed of the raised exception. 349 It ensures that the debug server is informed of the raised exception.
344 """ 350 """
345 self.pendingResponse = ResponseException 351 self.pendingResponse = ResponseException
346 352
347 def sessionClose(self, exit = 1): 353 def sessionClose(self, exit=1):
348 """ 354 """
349 Public method to close the session with the debugger and optionally terminate. 355 Public method to close the session with the debugger and optionally terminate.
350 356
351 @param exit flag indicating to terminate (boolean) 357 @param exit flag indicating to terminate (boolean)
352 """ 358 """
368 374
369 if exit: 375 if exit:
370 # Ok, go away. 376 # Ok, go away.
371 sys.exit() 377 sys.exit()
372 378
373 def handleLine(self,line): 379 def handleLine(self, line):
374 """ 380 """
375 Public method to handle the receipt of a complete line. 381 Public method to handle the receipt of a complete line.
376 382
377 It first looks for a valid protocol token at the start of the line. Thereafter 383 It first looks for a valid protocol token at the start of the line. Thereafter
378 it trys to execute the lines accumulated so far. 384 it trys to execute the lines accumulated so far.
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
479 self.mainFrame = None 485 self.mainFrame = None
480 self.inRawMode = 0 486 self.inRawMode = 0
481 self.debugging = 1 487 self.debugging = 1
482 488
483 self.threads.clear() 489 self.threads.clear()
484 self.attachThread(mainThread = 1) 490 self.attachThread(mainThread=1)
485 491
486 # set the system exception handling function to ensure, that 492 # set the system exception handling function to ensure, that
487 # we report on all unhandled exceptions 493 # we report on all unhandled exceptions
488 sys.excepthook = self.__unhandled_exception 494 sys.excepthook = self.__unhandled_exception
489 495
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:
520 self.mainFrame = None 526 self.mainFrame = None
521 self.botframe = None 527 self.botframe = None
522 self.inRawMode = 0 528 self.inRawMode = 0
523 529
524 self.threads.clear() 530 self.threads.clear()
525 self.attachThread(mainThread = 1) 531 self.attachThread(mainThread=1)
526 532
527 # set the system exception handling function to ensure, that 533 # set the system exception handling function to ensure, that
528 # we report on all unhandled exceptions 534 # we report on all unhandled exceptions
529 sys.excepthook = self.__unhandled_exception 535 sys.excepthook = self.__unhandled_exception
530 536
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
711 list[len(list):] = \ 717 list[len(list):] = \
712 traceback.format_exception_only(type, value) 718 traceback.format_exception_only(type, value)
713 finally: 719 finally:
714 tblist = tb = None 720 tblist = tb = None
715 721
716 map(self.write,list) 722 map(self.write, list)
717 723
718 self.write(ResponseException + '\n') 724 self.write(ResponseException + '\n')
719 725
720 else: 726 else:
721 self.write(unicode(value) + '\n') 727 self.write(unicode(value) + '\n')
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)
798 return 804 return
799 805
800 # generate a coverage object 806 # generate a coverage object
801 if int(cov): 807 if int(cov):
802 from coverage import coverage 808 from coverage import coverage
803 self.cover = coverage(auto_data = True, 809 self.cover = coverage(auto_data=True,
804 data_file = "%s.coverage" % os.path.splitext(covname)[0]) 810 data_file="%s.coverage" % os.path.splitext(covname)[0])
805 self.cover.use_cache(True) 811 self.cover.use_cache(True)
806 if int(erase): 812 if int(erase):
807 self.cover.erase() 813 self.cover.erase()
808 else: 814 else:
809 self.cover = None 815 self.cover = None
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:
939 pass 945 pass
940 return self.clientCapabilities 946 return self.clientCapabilities
941 except ImportError: 947 except ImportError:
942 return self.clientCapabilities & ~DebugClientCapabilities.HasProfiler 948 return self.clientCapabilities & ~DebugClientCapabilities.HasProfiler
943 949
944 def write(self,s): 950 def write(self, s):
945 """ 951 """
946 Public method to write data to the output stream. 952 Public method to write data to the output stream.
947 953
948 @param s data to be written (string) 954 @param s data to be written (string)
949 """ 955 """
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
1146 """ 1152 """
1147 Public method to return the main script we are currently running. 1153 Public method to return the main script we are currently running.
1148 """ 1154 """
1149 return self.running 1155 return self.running
1150 1156
1151 def progTerminated(self,status): 1157 def progTerminated(self, status):
1152 """ 1158 """
1153 Public method to tell the debugger that the program has terminated. 1159 Public method to tell the debugger that the program has terminated.
1154 1160
1155 @param status the return status 1161 @param status the return status
1156 """ 1162 """
1163 status = 1 1169 status = 1
1164 1170
1165 if self.running: 1171 if self.running:
1166 self.set_quit() 1172 self.set_quit()
1167 self.running = None 1173 self.running = None
1168 self.write('%s%d\n' % (ResponseExit,status)) 1174 self.write('%s%d\n' % (ResponseExit, status))
1169 1175
1170 # reset coding 1176 # reset coding
1171 self.__coding = self.defaultCoding 1177 self.__coding = self.defaultCoding
1172 1178
1173 def __dumpVariables(self, frmnr, scope, filter): 1179 def __dumpVariables(self, frmnr, scope, filter):
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 = ''
1303 if access: 1309 if access:
1304 if oaccess: 1310 if oaccess:
1305 access = '%s[%s]' % (oaccess, var[i]) 1311 access = '%s[%s]' % (oaccess, var[i])
1306 else: 1312 else:
1307 access = '%s[%s]' % (access, var[i]) 1313 access = '%s[%s]' % (access, var[i])
1308 if var[i-1][:-2] == '...': 1314 if var[i - 1][:-2] == '...':
1309 oaccess = access 1315 oaccess = access
1310 else: 1316 else:
1311 oaccess = '' 1317 oaccess = ''
1312 try: 1318 try:
1313 exec 'mdict = dict%s.__dict__' % access 1319 exec 'mdict = dict%s.__dict__' % access
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
1563 valtype = 'module' 1569 valtype = 'module'
1564 else: 1570 else:
1565 value = dict[key] 1571 value = dict[key]
1566 valtypestr = ("%s" % type(value))[1:-1] 1572 valtypestr = ("%s" % type(value))[1:-1]
1567 1573
1568 if valtypestr.split(' ',1)[0] == 'class': 1574 if valtypestr.split(' ', 1)[0] == 'class':
1569 # handle new class type of python 2.2+ 1575 # handle new class type of python 2.2+
1570 if ConfigVarTypeStrings.index('instance') in filter: 1576 if ConfigVarTypeStrings.index('instance') in filter:
1571 continue 1577 continue
1572 valtype = valtypestr 1578 valtype = valtypestr
1573 else: 1579 else:
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(';'):
1636 while pos >= -len(text): 1642 while pos >= -len(text):
1637 if text[pos] in completerDelims: 1643 if text[pos] in completerDelims:
1638 if pos == -1: 1644 if pos == -1:
1639 text = '' 1645 text = ''
1640 else: 1646 else:
1641 text = text[pos+1:] 1647 text = text[pos + 1:]
1642 break 1648 break
1643 pos -= 1 1649 pos -= 1
1644 1650
1645 try: 1651 try:
1646 comp = self.complete(text, state) 1652 comp = self.complete(text, state)
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, '')

eric ide

mercurial