DebugClients/Python3/DebugClientBase.py

changeset 945
8cd4d08fa9f6
parent 935
bf9ee1e00bc5
child 1029
0fb3d1d26eab
equal deleted inserted replaced
944:1b59c4ba121e 945:8cd4d08fa9f6
28 28
29 DebugClientInstance = None 29 DebugClientInstance = None
30 30
31 ################################################################################ 31 ################################################################################
32 32
33 def DebugClientInput(prompt = "", echo = True): 33
34 def DebugClientInput(prompt="", echo=True):
34 """ 35 """
35 Replacement for the standard input builtin. 36 Replacement for the standard input builtin.
36 37
37 This function works with the split debugger. 38 This function works with the split debugger.
38 39
52 DebugClientOrigInput = __main__.__builtins__.__dict__['input'] 53 DebugClientOrigInput = __main__.__builtins__.__dict__['input']
53 __main__.__builtins__.__dict__['input'] = DebugClientInput 54 __main__.__builtins__.__dict__['input'] = DebugClientInput
54 55
55 ################################################################################ 56 ################################################################################
56 57
58
57 def DebugClientFork(): 59 def DebugClientFork():
58 """ 60 """
59 Replacement for the standard os.fork(). 61 Replacement for the standard os.fork().
60 """ 62 """
61 if DebugClientInstance is None: 63 if DebugClientInstance is None:
68 DebugClientOrigFork = os.fork 70 DebugClientOrigFork = os.fork
69 os.fork = DebugClientFork 71 os.fork = DebugClientFork
70 72
71 ################################################################################ 73 ################################################################################
72 74
75
73 def DebugClientClose(fd): 76 def DebugClientClose(fd):
74 """ 77 """
75 Replacement for the standard os.close(fd). 78 Replacement for the standard os.close(fd).
76 79
77 @param fd open file descriptor to be closed (integer) 80 @param fd open file descriptor to be closed (integer)
85 if 'close' in dir(os): 88 if 'close' in dir(os):
86 DebugClientOrigClose = os.close 89 DebugClientOrigClose = os.close
87 os.close = DebugClientClose 90 os.close = DebugClientClose
88 91
89 ################################################################################ 92 ################################################################################
93
90 94
91 def DebugClientSetRecursionLimit(limit): 95 def DebugClientSetRecursionLimit(limit):
92 """ 96 """
93 Replacement for the standard sys.setrecursionlimit(limit). 97 Replacement for the standard sys.setrecursionlimit(limit).
94 98
104 sys.setrecursionlimit = DebugClientSetRecursionLimit 108 sys.setrecursionlimit = DebugClientSetRecursionLimit
105 DebugClientSetRecursionLimit(sys.getrecursionlimit()) 109 DebugClientSetRecursionLimit(sys.getrecursionlimit())
106 110
107 ################################################################################ 111 ################################################################################
108 112
113
109 class DebugClientBase(object): 114 class DebugClientBase(object):
110 """ 115 """
111 Class implementing the client side of the debugger. 116 Class implementing the client side of the debugger.
112 117
113 It provides access to the Python interpeter from a debugger running in another 118 It provides access to the Python interpeter from a debugger running in another
118 statements. Commands and statement are always exactly one line and may be 123 statements. Commands and statement are always exactly one line and may be
119 interspersed. 124 interspersed.
120 125
121 The protocol is as follows. First the client opens a connection to the 126 The protocol is as follows. First the client opens a connection to the
122 debugger and then sends a series of one line commands. A command is either 127 debugger and then sends a series of one line commands. A command is either
123 >Load<, >Step<, >StepInto<, ... or a Python statement. 128 >Load<, >Step<, >StepInto<, ... or a Python statement.
124 See DebugProtocol.py for a listing of valid protocol tokens. 129 See DebugProtocol.py for a listing of valid protocol tokens.
125 130
126 A Python statement consists of the statement to execute, followed (in a 131 A Python statement consists of the statement to execute, followed (in a
127 separate line) by >OK?<. If the statement was incomplete then the response 132 separate line) by >OK?<. If the statement was incomplete then the response
128 is >Continue<. If there was an exception then the response is 133 is >Continue<. If there was an exception then the response is
129 >Exception<. 134 >Exception<.
130 Otherwise the response is >OK<. The reason for the >OK?< part is to 135 Otherwise the response is >OK<. The reason for the >OK?< part is to
131 provide a sentinal (ie. the responding >OK<) after any possible output as a 136 provide a sentinal (ie. the responding >OK<) after any possible output as a
132 result of executing the command. 137 result of executing the command.
133 138
241 if m: 246 if m:
242 self.__coding = m.group(1) 247 self.__coding = m.group(1)
243 return 248 return
244 self.__coding = default 249 self.__coding = default
245 250
246 def attachThread(self, target = None, args = None, kwargs = None, mainThread = False): 251 def attachThread(self, target=None, args=None, kwargs=None, mainThread=False):
247 """ 252 """
248 Public method to setup a thread for DebugClient to debug. 253 Public method to setup a thread for DebugClient to debug.
249 254
250 If mainThread is non-zero, then we are attaching to the already 255 If mainThread is non-zero, then we are attaching to the already
251 started mainthread of the app and the rest of the args are ignored. 256 started mainthread of the app and the rest of the args are ignored.
252 257
253 @param target the start function of the target thread (i.e. the user code) 258 @param target the start function of the target thread (i.e. the user code)
254 @param args arguments to pass to target 259 @param args arguments to pass to target
255 @param kwargs keyword arguments to pass to target 260 @param kwargs keyword arguments to pass to target
256 @param mainThread True, if we are attaching to the already 261 @param mainThread True, if we are attaching to the already
257 started mainthread of the app 262 started mainthread of the app
258 @return The identifier of the created thread 263 @return The identifier of the created thread
259 """ 264 """
260 if self.debugging: 265 if self.debugging:
261 sys.setprofile(self.profile) 266 sys.setprofile(self.profile)
281 d["broken"] = self.isBroken() 286 d["broken"] = self.isBroken()
282 threadList.append(d) 287 threadList.append(d)
283 288
284 self.write("{0}{1!r}\n".format(ResponseThreadList, (currentId, threadList))) 289 self.write("{0}{1!r}\n".format(ResponseThreadList, (currentId, threadList)))
285 290
286 def input(self, prompt, echo = True): 291 def input(self, prompt, echo=True):
287 """ 292 """
288 Public method to implement input() using the event loop. 293 Public method to implement input() using the event loop.
289 294
290 @param prompt the prompt to be shown (string) 295 @param prompt the prompt to be shown (string)
291 @param echo Flag indicating echoing of the input (boolean) 296 @param echo Flag indicating echoing of the input (boolean)
302 307
303 It ensures that the debug server is informed of the raised exception. 308 It ensures that the debug server is informed of the raised exception.
304 """ 309 """
305 self.pendingResponse = ResponseException 310 self.pendingResponse = ResponseException
306 311
307 def sessionClose(self, exit = True): 312 def sessionClose(self, exit=True):
308 """ 313 """
309 Public method to close the session with the debugger and optionally terminate. 314 Public method to close the session with the debugger and optionally terminate.
310 315
311 @param exit flag indicating to terminate (boolean) 316 @param exit flag indicating to terminate (boolean)
312 """ 317 """
328 333
329 if exit: 334 if exit:
330 # Ok, go away. 335 # Ok, go away.
331 sys.exit() 336 sys.exit()
332 337
333 def __compileFileSource(self, filename, mode = 'exec'): 338 def __compileFileSource(self, filename, mode='exec'):
334 """ 339 """
335 Private method to compile source code read from a file. 340 Private method to compile source code read from a file.
336 341
337 @param filename name of the source file (string) 342 @param filename name of the source file (string)
338 @param mode kind of code to be generated (string, exec or eval) 343 @param mode kind of code to be generated (string, exec or eval)
339 @return compiled code object (None in case of errors) 344 @return compiled code object (None in case of errors)
340 """ 345 """
341 with open(filename, encoding = self.__coding) as fp: 346 with open(filename, encoding=self.__coding) as fp:
342 statement = fp.read() 347 statement = fp.read()
343 348
344 try: 349 try:
345 code = compile(statement + '\n', filename, mode) 350 code = compile(statement + '\n', filename, mode)
346 except SyntaxError: 351 except SyntaxError:
355 self.write("{0}{1}\n".format(ResponseSyntax, str(exclist))) 360 self.write("{0}{1}\n".format(ResponseSyntax, str(exclist)))
356 return None 361 return None
357 362
358 return code 363 return code
359 364
360 def handleLine(self,line): 365 def handleLine(self, line):
361 """ 366 """
362 Public method to handle the receipt of a complete line. 367 Public method to handle the receipt of a complete line.
363 368
364 It first looks for a valid protocol token at the start of the line. Thereafter 369 It first looks for a valid protocol token at the start of the line. Thereafter
365 it trys to execute the lines accumulated so far. 370 it trys to execute the lines accumulated so far.
466 self.mainFrame = None 471 self.mainFrame = None
467 self.inRawMode = False 472 self.inRawMode = False
468 self.debugging = True 473 self.debugging = True
469 474
470 self.threads.clear() 475 self.threads.clear()
471 self.attachThread(mainThread = True) 476 self.attachThread(mainThread=True)
472 477
473 # set the system exception handling function to ensure, that 478 # set the system exception handling function to ensure, that
474 # we report on all unhandled exceptions 479 # we report on all unhandled exceptions
475 sys.excepthook = self.__unhandled_exception 480 sys.excepthook = self.__unhandled_exception
476 481
480 self.mainThread.tracePython = tracePython 485 self.mainThread.tracePython = tracePython
481 486
482 # This will eventually enter a local event loop. 487 # This will eventually enter a local event loop.
483 # Note the use of backquotes to cause a repr of self.running. The 488 # Note the use of backquotes to cause a repr of self.running. The
484 # need for this is on Windows os where backslash is the path separator. 489 # need for this is on Windows os where backslash is the path separator.
485 # They will get inadvertantly stripped away during the eval causing 490 # They will get inadvertantly stripped away during the eval causing
486 # IOErrors, if self.running is passed as a normal str. 491 # IOErrors, if self.running is passed as a normal str.
487 self.debugMod.__dict__['__file__'] = self.running 492 self.debugMod.__dict__['__file__'] = self.running
488 sys.modules['__main__'] = self.debugMod 493 sys.modules['__main__'] = self.debugMod
489 code = self.__compileFileSource(self.running) 494 code = self.__compileFileSource(self.running)
490 if code: 495 if code:
508 self.mainFrame = None 513 self.mainFrame = None
509 self.botframe = None 514 self.botframe = None
510 self.inRawMode = False 515 self.inRawMode = False
511 516
512 self.threads.clear() 517 self.threads.clear()
513 self.attachThread(mainThread = True) 518 self.attachThread(mainThread=True)
514 519
515 # set the system exception handling function to ensure, that 520 # set the system exception handling function to ensure, that
516 # we report on all unhandled exceptions 521 # we report on all unhandled exceptions
517 sys.excepthook = self.__unhandled_exception 522 sys.excepthook = self.__unhandled_exception
518 523
519 self.mainThread.tracePython = False 524 self.mainThread.tracePython = False
520 525
521 self.debugMod.__dict__['__file__'] = sys.argv[0] 526 self.debugMod.__dict__['__file__'] = sys.argv[0]
522 sys.modules['__main__'] = self.debugMod 527 sys.modules['__main__'] = self.debugMod
523 exec(open(sys.argv[0], encoding = self.__coding).read(), 528 exec(open(sys.argv[0], encoding=self.__coding).read(),
524 self.debugMod.__dict__) 529 self.debugMod.__dict__)
525 self.writestream.flush() 530 self.writestream.flush()
526 return 531 return
527 532
528 if cmd == RequestProfile: 533 if cmd == RequestProfile:
548 553
549 if int(erase): 554 if int(erase):
550 self.prof.erase() 555 self.prof.erase()
551 self.debugMod.__dict__['__file__'] = sys.argv[0] 556 self.debugMod.__dict__['__file__'] = sys.argv[0]
552 sys.modules['__main__'] = self.debugMod 557 sys.modules['__main__'] = self.debugMod
553 fp = open(sys.argv[0], encoding = self.__coding) 558 fp = open(sys.argv[0], encoding=self.__coding)
554 try: 559 try:
555 script = fp.read() 560 script = fp.read()
556 finally: 561 finally:
557 fp.close() 562 fp.close()
558 if script: 563 if script:
577 # set the system exception handling function to ensure, that 582 # set the system exception handling function to ensure, that
578 # we report on all unhandled exceptions 583 # we report on all unhandled exceptions
579 sys.excepthook = self.__unhandled_exception 584 sys.excepthook = self.__unhandled_exception
580 585
581 # generate a coverage object 586 # generate a coverage object
582 self.cover = coverage(auto_data = True, 587 self.cover = coverage(auto_data=True,
583 data_file = "{0}.coverage".format(os.path.splitext(sys.argv[0])[0])) 588 data_file="{0}.coverage".format(os.path.splitext(sys.argv[0])[0]))
584 self.cover.use_cache(True) 589 self.cover.use_cache(True)
585 590
586 if int(erase): 591 if int(erase):
587 self.cover.erase() 592 self.cover.erase()
588 sys.modules['__main__'] = self.debugMod 593 sys.modules['__main__'] = self.debugMod
589 self.debugMod.__dict__['__file__'] = sys.argv[0] 594 self.debugMod.__dict__['__file__'] = sys.argv[0]
590 self.cover.start() 595 self.cover.start()
591 exec(open(sys.argv[0], encoding = self.__coding).read(), 596 exec(open(sys.argv[0], encoding=self.__coding).read(),
592 self.debugMod.__dict__) 597 self.debugMod.__dict__)
593 self.cover.stop() 598 self.cover.stop()
594 self.cover.save() 599 self.cover.save()
595 self.writestream.flush() 600 self.writestream.flush()
596 return 601 return
749 self.write(ResponseException + '\n') 754 self.write(ResponseException + '\n')
750 755
751 return 756 return
752 757
753 if cmd == RequestBanner: 758 if cmd == RequestBanner:
754 self.write('{0}{1}\n'.format(ResponseBanner, 759 self.write('{0}{1}\n'.format(ResponseBanner,
755 str(("Python {0}".format(sys.version), 760 str(("Python {0}".format(sys.version),
756 socket.gethostname(), self.variant)))) 761 socket.gethostname(), self.variant))))
757 return 762 return
758 763
759 if cmd == RequestCapabilities: 764 if cmd == RequestCapabilities:
760 self.write('{0}{1:d}, "Python3"\n'.format(ResponseCapabilities, 765 self.write('{0}{1:d}, "Python3"\n'.format(ResponseCapabilities,
761 self.__clientCapabilities())) 766 self.__clientCapabilities()))
762 return 767 return
763 768
764 if cmd == RequestCompletion: 769 if cmd == RequestCompletion:
765 self.__completionList(arg.replace("u'", "'")) 770 self.__completionList(arg.replace("u'", "'"))
796 return 801 return
797 802
798 # generate a coverage object 803 # generate a coverage object
799 if int(cov): 804 if int(cov):
800 from coverage import coverage 805 from coverage import coverage
801 self.cover = coverage(auto_data = True, 806 self.cover = coverage(auto_data=True,
802 data_file = "{0}.coverage".format(os.path.splitext(covname)[0])) 807 data_file="{0}.coverage".format(os.path.splitext(covname)[0]))
803 self.cover.use_cache(True) 808 self.cover.use_cache(True)
804 if int(erase): 809 if int(erase):
805 self.cover.erase() 810 self.cover.erase()
806 else: 811 else:
807 self.cover = None 812 self.cover = None
860 865
861 self.__exceptionRaised() 866 self.__exceptionRaised()
862 else: 867 else:
863 if code is None: 868 if code is None:
864 self.pendingResponse = ResponseContinue 869 self.pendingResponse = ResponseContinue
865 else: 870 else:
866 self.buffer = '' 871 self.buffer = ''
867 872
868 try: 873 try:
869 if self.running is None: 874 if self.running is None:
870 exec(code, self.debugMod.__dict__) 875 exec(code, self.debugMod.__dict__)
939 pass 944 pass
940 return self.clientCapabilities 945 return self.clientCapabilities
941 except ImportError: 946 except ImportError:
942 return self.clientCapabilities & ~DebugClientCapabilities.HasProfiler 947 return self.clientCapabilities & ~DebugClientCapabilities.HasProfiler
943 948
944 def write(self,s): 949 def write(self, s):
945 """ 950 """
946 Public method to write data to the output stream. 951 Public method to write data to the output stream.
947 952
948 @param s data to be written (string) 953 @param s data to be written (string)
949 """ 954 """
961 966
962 if not self.passive: 967 if not self.passive:
963 # At this point simulate an event loop. 968 # At this point simulate an event loop.
964 self.eventLoop() 969 self.eventLoop()
965 970
966 def eventLoop(self, disablePolling = False): 971 def eventLoop(self, disablePolling=False):
967 """ 972 """
968 Public method implementing our event loop. 973 Public method implementing our event loop.
969 974
970 @param disablePolling flag indicating to enter an event loop with 975 @param disablePolling flag indicating to enter an event loop with
971 polling disabled (boolean) 976 polling disabled (boolean)
1036 self.writeReady(self.writestream.fileno()) 1041 self.writeReady(self.writestream.fileno())
1037 1042
1038 if self.errorstream in wrdy: 1043 if self.errorstream in wrdy:
1039 self.writeReady(self.errorstream.fileno()) 1044 self.writeReady(self.errorstream.fileno())
1040 1045
1041 def connectDebugger(self, port, remoteAddress = None, redirect = True): 1046 def connectDebugger(self, port, remoteAddress=None, redirect=True):
1042 """ 1047 """
1043 Public method to establish a session with the debugger. 1048 Public method to establish a session with the debugger.
1044 1049
1045 It opens a network connection to the debugger, connects it to stdin, 1050 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 1051 stdout and stderr and saves these file objects in case the application
1047 being debugged redirects them itself. 1052 being debugged redirects them itself.
1048 1053
1049 @param port the port number to connect to (int) 1054 @param port the port number to connect to (int)
1050 @param remoteAddress the network address of the debug server host (string) 1055 @param remoteAddress the network address of the debug server host (string)
1069 sys.stdout = self.writestream 1074 sys.stdout = self.writestream
1070 sys.stderr = self.errorstream 1075 sys.stderr = self.errorstream
1071 self.redirect = redirect 1076 self.redirect = redirect
1072 1077
1073 # attach to the main thread here 1078 # attach to the main thread here
1074 self.attachThread(mainThread = True) 1079 self.attachThread(mainThread=True)
1075 1080
1076 def __unhandled_exception(self, exctype, excval, exctb): 1081 def __unhandled_exception(self, exctype, excval, exctb):
1077 """ 1082 """
1078 Private method called to report an uncaught exception. 1083 Private method called to report an uncaught exception.
1079 1084
1085 1090
1086 def absPath(self, fn): 1091 def absPath(self, fn):
1087 """ 1092 """
1088 Public method to convert a filename to an absolute name. 1093 Public method to convert a filename to an absolute name.
1089 1094
1090 sys.path is used as a set of possible prefixes. The name stays 1095 sys.path is used as a set of possible prefixes. The name stays
1091 relative if a file could not be found. 1096 relative if a file could not be found.
1092 1097
1093 @param fn filename (string) 1098 @param fn filename (string)
1094 @return the converted filename (string) 1099 @return the converted filename (string)
1095 """ 1100 """
1137 # Eliminate anything that is part of the Python installation. 1142 # Eliminate anything that is part of the Python installation.
1138 afn = self.absPath(fn) 1143 afn = self.absPath(fn)
1139 for d in self.skipdirs: 1144 for d in self.skipdirs:
1140 if afn.startswith(d): 1145 if afn.startswith(d):
1141 return True 1146 return True
1142
1143 1147
1144 return False 1148 return False
1145 1149
1146 def getRunning(self): 1150 def getRunning(self):
1147 """ 1151 """
1304 if access: 1308 if access:
1305 if oaccess: 1309 if oaccess:
1306 access = '{0!s}[{1!s}]'.format(oaccess, var[i]) 1310 access = '{0!s}[{1!s}]'.format(oaccess, var[i])
1307 else: 1311 else:
1308 access = '{0!s}[{1!s}]'.format(access, var[i]) 1312 access = '{0!s}[{1!s}]'.format(access, var[i])
1309 if var[i-1][:-2] == '...': 1313 if var[i - 1][:-2] == '...':
1310 oaccess = access 1314 oaccess = access
1311 else: 1315 else:
1312 oaccess = '' 1316 oaccess = ''
1313 try: 1317 try:
1314 loc = {"dict" : dict} 1318 loc = {"dict": dict}
1315 exec('mdict = dict{0!s}.__dict__\nobj = dict{0!s}'\ 1319 exec('mdict = dict{0!s}.__dict__\nobj = dict{0!s}'\
1316 .format(access), globals(), loc) 1320 .format(access), globals(), loc)
1317 mdict = loc["mdict"] 1321 mdict = loc["mdict"]
1318 obj = loc["obj"] 1322 obj = loc["obj"]
1319 ndict.update(mdict) 1323 ndict.update(mdict)
1321 del rvar[0:2] 1325 del rvar[0:2]
1322 access = "" 1326 access = ""
1323 except: 1327 except:
1324 pass 1328 pass
1325 try: 1329 try:
1326 loc = {"cdict" : {}, "dict" : dict} 1330 loc = {"cdict": {}, "dict": dict}
1327 exec('slv = dict{0!s}.__slots__'.format(access), 1331 exec('slv = dict{0!s}.__slots__'.format(access),
1328 globals(), loc) 1332 globals(), loc)
1329 for v in loc["slv"]: 1333 for v in loc["slv"]:
1330 try: 1334 try:
1331 loc["v"] = v 1335 loc["v"] = v
1332 exec('cdict[v] = dict{0!s}.{1!s}'.format(access, v), 1336 exec('cdict[v] = dict{0!s}.{1!s}'.format(access, v),
1333 globals, loc) 1337 globals, loc)
1334 except: 1338 except:
1335 pass 1339 pass
1336 ndict.update(loc["cdict"]) 1340 ndict.update(loc["cdict"])
1337 exec('obj = dict{0!s}'.format(access), globals(), loc) 1341 exec('obj = dict{0!s}'.format(access), globals(), loc)
1346 obj = dict[var[i]] 1350 obj = dict[var[i]]
1347 except: 1351 except:
1348 pass 1352 pass
1349 try: 1353 try:
1350 slv = dict[var[i]].__slots__ 1354 slv = dict[var[i]].__slots__
1351 loc = {"cdict" : {}, "dict" : dict, "var" : var, "i" : i} 1355 loc = {"cdict": {}, "dict": dict, "var": var, "i": i}
1352 for v in slv: 1356 for v in slv:
1353 try: 1357 try:
1354 loc["v"] = v 1358 loc["v"] = v
1355 exec('cdict[v] = dict[var[i]].{0!s}'.format(v), 1359 exec('cdict[v] = dict[var[i]].{0!s}'.format(v),
1356 globals(), loc) 1360 globals(), loc)
1357 except: 1361 except:
1358 pass 1362 pass
1359 ndict.update(loc["cdict"]) 1363 ndict.update(loc["cdict"])
1360 obj = dict[var[i]] 1364 obj = dict[var[i]]
1365 i += 1 1369 i += 1
1366 1370
1367 if ("sipThis" in dict.keys() and len(dict) == 1) or \ 1371 if ("sipThis" in dict.keys() and len(dict) == 1) or \
1368 (len(dict) == 0 and len(udict) > 0): 1372 (len(dict) == 0 and len(udict) > 0):
1369 if access: 1373 if access:
1370 loc = {"udict" : udict} 1374 loc = {"udict": udict}
1371 exec('qvar = udict{0!s}'.format(access), globals(), loc) 1375 exec('qvar = udict{0!s}'.format(access), globals(), loc)
1372 qvar = loc["qvar"] 1376 qvar = loc["qvar"]
1373 # this has to be in line with VariablesViewer.indicators 1377 # this has to be in line with VariablesViewer.indicators
1374 elif rvar and rvar[0][-2:] in ["[]", "()", "{}"]: 1378 elif rvar and rvar[0][-2:] in ["[]", "()", "{}"]:
1375 loc = {"udict" : udict} 1379 loc = {"udict": udict}
1376 exec('qvar = udict["{0!s}"][{1!s}]'.format(rvar[0][:-2], rvar[1]), 1380 exec('qvar = udict["{0!s}"][{1!s}]'.format(rvar[0][:-2], rvar[1]),
1377 globals(), loc) 1381 globals(), loc)
1378 qvar = loc["qvar"] 1382 qvar = loc["qvar"]
1379 else: 1383 else:
1380 qvar = udict[var[-1]] 1384 qvar = udict[var[-1]]
1381 qvtype = str(type(qvar))[1:-1].split()[1][1:-1] 1385 qvtype = str(type(qvar))[1:-1].split()[1][1:-1]
1388 if dictkeys is None: 1392 if dictkeys is None:
1389 dictkeys = dict.keys() 1393 dictkeys = dict.keys()
1390 else: 1394 else:
1391 # treatment for sequences and dictionaries 1395 # treatment for sequences and dictionaries
1392 if access: 1396 if access:
1393 loc = {"dict" : dict} 1397 loc = {"dict": dict}
1394 exec("dict = dict{0!s}".format(access), globals(), loc) 1398 exec("dict = dict{0!s}".format(access), globals(), loc)
1395 dict = loc["dict"] 1399 dict = loc["dict"]
1396 else: 1400 else:
1397 dict = dict[dictkeys[0]] 1401 dict = dict[dictkeys[0]]
1398 if isDict: 1402 if isDict:
1399 dictkeys = dict.keys() 1403 dictkeys = dict.keys()
1400 else: 1404 else:
1401 dictkeys = range(len(dict)) 1405 dictkeys = range(len(dict))
1402 vlist = self.__formatVariablesList(dictkeys, dict, scope, filter, 1406 vlist = self.__formatVariablesList(dictkeys, dict, scope, filter,
1403 formatSequences) 1407 formatSequences)
1404 varlist.extend(vlist) 1408 varlist.extend(vlist)
1405 1409
1406 if obj is not None and not formatSequences: 1410 if obj is not None and not formatSequences:
1407 if repr(obj).startswith('{'): 1411 if repr(obj).startswith('{'):
1417 """ 1421 """
1418 Private method to produce a formatted output of a simple Qt4 type. 1422 Private method to produce a formatted output of a simple Qt4 type.
1419 1423
1420 @param value variable to be formatted 1424 @param value variable to be formatted
1421 @param vtype type of the variable to be formatted (string) 1425 @param vtype type of the variable to be formatted (string)
1422 @return A tuple consisting of a list of formatted variables. Each 1426 @return A tuple consisting of a list of formatted variables. Each
1423 variable entry is a tuple of three elements, the variable name, 1427 variable entry is a tuple of three elements, the variable name,
1424 its type and value. 1428 its type and value.
1425 """ 1429 """
1426 qttype = vtype.split('.')[-1] 1430 qttype = vtype.split('.')[-1]
1427 varlist = [] 1431 varlist = []
1428 if qttype == 'QChar': 1432 if qttype == 'QChar':
1451 varlist.append(("width", "float", "{0:g}".format(value.width()))) 1455 varlist.append(("width", "float", "{0:g}".format(value.width())))
1452 varlist.append(("height", "float", "{0:g}".format(value.height()))) 1456 varlist.append(("height", "float", "{0:g}".format(value.height())))
1453 elif qttype == 'QColor': 1457 elif qttype == 'QColor':
1454 varlist.append(("name", "str", "{0}".format(value.name()))) 1458 varlist.append(("name", "str", "{0}".format(value.name())))
1455 r, g, b, a = value.getRgb() 1459 r, g, b, a = value.getRgb()
1456 varlist.append(("rgb", "int", 1460 varlist.append(("rgb", "int",
1457 "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a))) 1461 "{0:d}, {1:d}, {2:d}, {3:d}".format(r, g, b, a)))
1458 h, s, v, a = value.getHsv() 1462 h, s, v, a = value.getHsv()
1459 varlist.append(("hsv", "int", 1463 varlist.append(("hsv", "int",
1460 "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a))) 1464 "{0:d}, {1:d}, {2:d}, {3:d}".format(h, s, v, a)))
1461 c, m, y, k, a = value.getCmyk() 1465 c, m, y, k, a = value.getCmyk()
1462 varlist.append(("cmyk", "int", 1466 varlist.append(("cmyk", "int",
1463 "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a))) 1467 "{0:d}, {1:d}, {2:d}, {3:d}, {4:d}".format(c, m, y, k, a)))
1464 elif qttype == 'QDate': 1468 elif qttype == 'QDate':
1465 varlist.append(("", "QDate", "{0}".format(value.toString()))) 1469 varlist.append(("", "QDate", "{0}".format(value.toString())))
1466 elif qttype == 'QTime': 1470 elif qttype == 'QTime':
1467 varlist.append(("", "QTime", "{0}".format(value.toString()))) 1471 varlist.append(("", "QTime", "{0}".format(value.toString())))
1468 elif qttype == 'QDateTime': 1472 elif qttype == 'QDateTime':
1469 varlist.append(("", "QDateTime", "{0}".format(value.toString()))) 1473 varlist.append(("", "QDateTime", "{0}".format(value.toString())))
1470 elif qttype == 'QDir': 1474 elif qttype == 'QDir':
1471 varlist.append(("path", "str", "{0}".format(value.path()))) 1475 varlist.append(("path", "str", "{0}".format(value.path())))
1472 varlist.append(("absolutePath", "str", 1476 varlist.append(("absolutePath", "str",
1473 "{0}".format(value.absolutePath()))) 1477 "{0}".format(value.absolutePath())))
1474 varlist.append(("canonicalPath", "str", 1478 varlist.append(("canonicalPath", "str",
1475 "{0}".format(value.canonicalPath()))) 1479 "{0}".format(value.canonicalPath())))
1476 elif qttype == 'QFile': 1480 elif qttype == 'QFile':
1477 varlist.append(("fileName", "str", "{0}".format(value.fileName()))) 1481 varlist.append(("fileName", "str", "{0}".format(value.fileName())))
1478 elif qttype == 'QFont': 1482 elif qttype == 'QFont':
1479 varlist.append(("family", "str", "{0}".format(value.family()))) 1483 varlist.append(("family", "str", "{0}".format(value.family())))
1493 varlist.append(("valid", "bool", "{0}".format(value.isValid()))) 1497 varlist.append(("valid", "bool", "{0}".format(value.isValid())))
1494 if value.isValid(): 1498 if value.isValid():
1495 varlist.append(("row", "int", "{0}".format(value.row()))) 1499 varlist.append(("row", "int", "{0}".format(value.row())))
1496 varlist.append(("column", "int", "{0}".format(value.column()))) 1500 varlist.append(("column", "int", "{0}".format(value.column())))
1497 varlist.append(("internalId", "int", "{0}".format(value.internalId()))) 1501 varlist.append(("internalId", "int", "{0}".format(value.internalId())))
1498 varlist.append(("internalPointer", "void *", 1502 varlist.append(("internalPointer", "void *",
1499 "{0}".format(value.internalPointer()))) 1503 "{0}".format(value.internalPointer())))
1500 elif qttype == 'QRegExp': 1504 elif qttype == 'QRegExp':
1501 varlist.append(("pattern", "str", "{0}".format(value.pattern()))) 1505 varlist.append(("pattern", "str", "{0}".format(value.pattern())))
1502 1506
1503 # GUI stuff 1507 # GUI stuff
1505 varlist.append(("name", "str", "{0}".format(value.objectName()))) 1509 varlist.append(("name", "str", "{0}".format(value.objectName())))
1506 varlist.append(("text", "str", "{0}".format(value.text()))) 1510 varlist.append(("text", "str", "{0}".format(value.text())))
1507 varlist.append(("icon text", "str", "{0}".format(value.iconText()))) 1511 varlist.append(("icon text", "str", "{0}".format(value.iconText())))
1508 varlist.append(("tooltip", "str", "{0}".format(value.toolTip()))) 1512 varlist.append(("tooltip", "str", "{0}".format(value.toolTip())))
1509 varlist.append(("whatsthis", "str", "{0}".format(value.whatsThis()))) 1513 varlist.append(("whatsthis", "str", "{0}".format(value.whatsThis())))
1510 varlist.append(("shortcut", "str", 1514 varlist.append(("shortcut", "str",
1511 "{0}".format(value.shortcut().toString()))) 1515 "{0}".format(value.shortcut().toString())))
1512 elif qttype == 'QKeySequence': 1516 elif qttype == 'QKeySequence':
1513 varlist.append(("value", "", "{0}".format(value.toString()))) 1517 varlist.append(("value", "", "{0}".format(value.toString())))
1514 1518
1515 # XML stuff 1519 # XML stuff
1532 elif qttype == 'QHostAddress': 1536 elif qttype == 'QHostAddress':
1533 varlist.append(("address", "QHostAddress", "{0}".format(value.toString()))) 1537 varlist.append(("address", "QHostAddress", "{0}".format(value.toString())))
1534 1538
1535 return varlist 1539 return varlist
1536 1540
1537 def __formatVariablesList(self, keylist, dict, scope, filter = [], 1541 def __formatVariablesList(self, keylist, dict, scope, filter=[],
1538 formatSequences = False): 1542 formatSequences=False):
1539 """ 1543 """
1540 Private method to produce a formated variables list. 1544 Private method to produce a formated variables list.
1541 1545
1542 The dictionary passed in to it is scanned. Variables are 1546 The dictionary passed in to it is scanned. Variables are
1543 only added to the list, if their type is not contained 1547 only added to the list, if their type is not contained
1544 in the filter list and their name doesn't match any of the filter expressions. 1548 in the filter list and their name doesn't match any of the filter expressions.
1545 The formated variables list (a list of tuples of 3 values) is returned. 1549 The formated variables list (a list of tuples of 3 values) is returned.
1546 1550
1547 @param keylist keys of the dictionary 1551 @param keylist keys of the dictionary
1548 @param dict the dictionary to be scanned 1552 @param dict the dictionary to be scanned
1549 @param scope 1 to filter using the globals filter, 0 using the locals 1553 @param scope 1 to filter using the globals filter, 0 using the locals
1550 filter (int). 1554 filter (int).
1551 Variables are only added to the list, if their name do not match any of the 1555 Variables are only added to the list, if their name do not match any of the
1552 filter expressions. 1556 filter expressions.
1553 @param filter the indices of variable types to be filtered. Variables are 1557 @param filter the indices of variable types to be filtered. Variables are
1554 only added to the list, if their type is not contained in the filter 1558 only added to the list, if their type is not contained in the filter
1555 list. 1559 list.
1556 @param formatSequences flag indicating, that sequence or dictionary variables 1560 @param formatSequences flag indicating, that sequence or dictionary variables
1557 should be formatted. If it is 0 (or false), just the number of items contained 1561 should be formatted. If it is 0 (or false), just the number of items contained
1558 in these variables is returned. (boolean) 1562 in these variables is returned. (boolean)
1559 @return A tuple consisting of a list of formatted variables. Each variable 1563 @return A tuple consisting of a list of formatted variables. Each variable
1560 entry is a tuple of three elements, the variable name, its type and 1564 entry is a tuple of three elements, the variable name, its type and
1561 value. 1565 value.
1562 """ 1566 """
1563 varlist = [] 1567 varlist = []
1564 if scope: 1568 if scope:
1565 patternFilterObjects = self.globalsFilterObjects 1569 patternFilterObjects = self.globalsFilterObjects
1629 1633
1630 def __generateFilterObjects(self, scope, filterString): 1634 def __generateFilterObjects(self, scope, filterString):
1631 """ 1635 """
1632 Private slot to convert a filter string to a list of filter objects. 1636 Private slot to convert a filter string to a list of filter objects.
1633 1637
1634 @param scope 1 to generate filter for global variables, 0 for local 1638 @param scope 1 to generate filter for global variables, 0 for local
1635 variables (int) 1639 variables (int)
1636 @param filterString string of filter patterns separated by ';' 1640 @param filterString string of filter patterns separated by ';'
1637 """ 1641 """
1638 patternFilterObjects = [] 1642 patternFilterObjects = []
1639 for pattern in filterString.split(';'): 1643 for pattern in filterString.split(';'):
1658 while pos >= -len(text): 1662 while pos >= -len(text):
1659 if text[pos] in completerDelims: 1663 if text[pos] in completerDelims:
1660 if pos == -1: 1664 if pos == -1:
1661 text = '' 1665 text = ''
1662 else: 1666 else:
1663 text = text[pos+1:] 1667 text = text[pos + 1:]
1664 break 1668 break
1665 pos -= 1 1669 pos -= 1
1666 1670
1667 try: 1671 try:
1668 comp = self.complete(text, state) 1672 comp = self.complete(text, state)
1676 except: 1680 except:
1677 comp = None 1681 comp = None
1678 1682
1679 self.write("{0}{1}||{2}\n".format(ResponseCompletion, str(completions), text)) 1683 self.write("{0}{1}||{2}\n".format(ResponseCompletion, str(completions), text))
1680 1684
1681 def startDebugger(self, filename = None, host = None, port = None, 1685 def startDebugger(self, filename=None, host=None, port=None,
1682 enableTrace = True, exceptions = True, tracePython = False, redirect = True): 1686 enableTrace=True, exceptions=True, tracePython=False, redirect=True):
1683 """ 1687 """
1684 Public method used to start the remote debugger. 1688 Public method used to start the remote debugger.
1685 1689
1686 @param filename the program to be debugged (string) 1690 @param filename the program to be debugged (string)
1687 @param host hostname of the debug server (string) 1691 @param host hostname of the debug server (string)
1717 self.dircache = [] 1721 self.dircache = []
1718 self.mainFrame = None 1722 self.mainFrame = None
1719 self.inRawMode = False 1723 self.inRawMode = False
1720 self.debugging = True 1724 self.debugging = True
1721 1725
1722 self.attachThread(mainThread = True) 1726 self.attachThread(mainThread=True)
1723 self.mainThread.tracePython = tracePython 1727 self.mainThread.tracePython = tracePython
1724 1728
1725 # set the system exception handling function to ensure, that 1729 # set the system exception handling function to ensure, that
1726 # we report on all unhandled exceptions 1730 # we report on all unhandled exceptions
1727 sys.excepthook = self.__unhandled_exception 1731 sys.excepthook = self.__unhandled_exception
1728 1732
1729 # now start debugging 1733 # now start debugging
1730 if enableTrace: 1734 if enableTrace:
1731 self.mainThread.set_trace() 1735 self.mainThread.set_trace()
1732 1736
1733 def startProgInDebugger(self, progargs, wd = '', host = None, 1737 def startProgInDebugger(self, progargs, wd='', host=None,
1734 port = None, exceptions = True, tracePython = False, redirect = True): 1738 port=None, exceptions=True, tracePython=False, redirect=True):
1735 """ 1739 """
1736 Public method used to start the remote debugger. 1740 Public method used to start the remote debugger.
1737 1741
1738 @param progargs commandline for the program to be debugged 1742 @param progargs commandline for the program to be debugged
1739 (list of strings) 1743 (list of strings)
1740 @param wd working directory for the program execution (string) 1744 @param wd working directory for the program execution (string)
1741 @param host hostname of the debug server (string) 1745 @param host hostname of the debug server (string)
1742 @param port portnumber of the debug server (int) 1746 @param port portnumber of the debug server (int)
1743 @param exceptions flag to enable exception reporting of the IDE (boolean) 1747 @param exceptions flag to enable exception reporting of the IDE (boolean)
1769 1773
1770 self.passive = True 1774 self.passive = True
1771 self.write("{0}{1}|{2:d}\n".format(PassiveStartup, self.running, exceptions)) 1775 self.write("{0}{1}|{2:d}\n".format(PassiveStartup, self.running, exceptions))
1772 self.__interact() 1776 self.__interact()
1773 1777
1774 self.attachThread(mainThread = True) 1778 self.attachThread(mainThread=True)
1775 self.mainThread.tracePython = tracePython 1779 self.mainThread.tracePython = tracePython
1776 1780
1777 # set the system exception handling function to ensure, that 1781 # set the system exception handling function to ensure, that
1778 # we report on all unhandled exceptions 1782 # we report on all unhandled exceptions
1779 sys.excepthook = self.__unhandled_exception 1783 sys.excepthook = self.__unhandled_exception
1796 @param scriptname name of the script to be debugged (string) 1800 @param scriptname name of the script to be debugged (string)
1797 @param func function to be called 1801 @param func function to be called
1798 @param *args arguments being passed to func 1802 @param *args arguments being passed to func
1799 @return result of the function call 1803 @return result of the function call
1800 """ 1804 """
1801 self.startDebugger(scriptname, enableTrace = False) 1805 self.startDebugger(scriptname, enableTrace=False)
1802 res = self.mainThread.runcall(func, *args) 1806 res = self.mainThread.runcall(func, *args)
1803 self.progTerminated(res) 1807 self.progTerminated(res)
1804 return res 1808 return res
1805 1809
1806 def __resolveHost(self, host): 1810 def __resolveHost(self, host):
1865 if not args: 1869 if not args:
1866 print("No program given. Aborting!") 1870 print("No program given. Aborting!")
1867 else: 1871 else:
1868 if not self.noencoding: 1872 if not self.noencoding:
1869 self.__coding = self.defaultCoding 1873 self.__coding = self.defaultCoding
1870 self.startProgInDebugger(args, wd, host, port, 1874 self.startProgInDebugger(args, wd, host, port,
1871 exceptions = exceptions, 1875 exceptions=exceptions,
1872 tracePython = tracePython, 1876 tracePython=tracePython,
1873 redirect = redirect) 1877 redirect=redirect)
1874 else: 1878 else:
1875 if sys.argv[1] == '--no-encoding': 1879 if sys.argv[1] == '--no-encoding':
1876 self.noencoding = True 1880 self.noencoding = True
1877 del sys.argv[1] 1881 del sys.argv[1]
1878 if sys.argv[1] == '': 1882 if sys.argv[1] == '':
1934 1938
1935 It prevents the debugger connections from being closed. 1939 It prevents the debugger connections from being closed.
1936 1940
1937 @param fd file descriptor to be closed (integer) 1941 @param fd file descriptor to be closed (integer)
1938 """ 1942 """
1939 if fd in [self.readstream.fileno(), self.writestream.fileno(), 1943 if fd in [self.readstream.fileno(), self.writestream.fileno(),
1940 self.errorstream.fileno()]: 1944 self.errorstream.fileno()]:
1941 return 1945 return
1942 1946
1943 DebugClientOrigClose(fd) 1947 DebugClientOrigClose(fd)
1944 1948
1945 def __getSysPath(self, firstEntry): 1949 def __getSysPath(self, firstEntry):
1946 """ 1950 """
1947 Private slot to calculate a path list including the PYTHONPATH 1951 Private slot to calculate a path list including the PYTHONPATH
1948 environment variable. 1952 environment variable.
1949 1953
1950 @param firstEntry entry to be put first in sys.path (string) 1954 @param firstEntry entry to be put first in sys.path (string)
1951 @return path list for use as sys.path (list of strings) 1955 @return path list for use as sys.path (list of strings)
1952 """ 1956 """
1953 sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep) 1957 sysPath = [path for path in os.environ.get("PYTHONPATH", "").split(os.pathsep)
1954 if path not in sys.path] + sys.path[:] 1958 if path not in sys.path] + sys.path[:]
1955 if "" in sysPath: 1959 if "" in sysPath:
1956 sysPath.remove("") 1960 sysPath.remove("")
1957 sysPath.insert(0, firstEntry) 1961 sysPath.insert(0, firstEntry)
1958 sysPath.insert(0, '') 1962 sysPath.insert(0, '')

eric ide

mercurial