DebugClients/Python/DebugClientBase.py

branch
jsonrpc
changeset 5132
a094eee9f862
parent 4944
d4709f4818bb
equal deleted inserted replaced
5131:889ed5ff7a68 5132:a094eee9f862
19 import atexit 19 import atexit
20 import signal 20 import signal
21 import inspect 21 import inspect
22 22
23 23
24 import DebugProtocol
25 import DebugClientCapabilities 24 import DebugClientCapabilities
26 from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__ 25 from DebugBase import setRecursionLimit, printerr # __IGNORE_WARNING__
27 from AsyncFile import AsyncFile, AsyncPendingWrite 26 from AsyncFile import AsyncFile, AsyncPendingWrite
28 from DebugConfig import ConfigVarTypeStrings 27 from DebugConfig import ConfigVarTypeStrings
29 from FlexCompleter import Completer 28 from FlexCompleter import Completer
29 from DebugUtilities import prepareJsonCommand
30 30
31 31
32 DebugClientInstance = None 32 DebugClientInstance = None
33 33
34 ############################################################################### 34 ###############################################################################
42 42
43 @param prompt prompt to be shown. (string) 43 @param prompt prompt to be shown. (string)
44 @param echo flag indicating echoing of the input (boolean) 44 @param echo flag indicating echoing of the input (boolean)
45 @return result of the raw_input() call 45 @return result of the raw_input() call
46 """ 46 """
47 if DebugClientInstance is None or DebugClientInstance.redirect == 0: 47 if DebugClientInstance is None or not DebugClientInstance.redirect:
48 return DebugClientOrigRawInput(prompt) 48 return DebugClientOrigRawInput(prompt)
49 49
50 return DebugClientInstance.raw_input(prompt, echo) 50 return DebugClientInstance.raw_input(prompt, echo)
51 51
52 # Use our own raw_input(). 52 # Use our own raw_input().
183 def __init__(self): 183 def __init__(self):
184 """ 184 """
185 Constructor 185 Constructor
186 """ 186 """
187 self.breakpoints = {} 187 self.breakpoints = {}
188 self.redirect = 1 188 self.redirect = True
189 self.__receiveBuffer = ""
189 190
190 # The next couple of members are needed for the threaded version. 191 # The next couple of members are needed for the threaded version.
191 # For this base class they contain static values for the non threaded 192 # For this base class they contain static values for the non threaded
192 # debugger 193 # debugger
193 194
212 213
213 # The list of regexp objects to filter variables against 214 # The list of regexp objects to filter variables against
214 self.globalsFilterObjects = [] 215 self.globalsFilterObjects = []
215 self.localsFilterObjects = [] 216 self.localsFilterObjects = []
216 217
217 self.pendingResponse = DebugProtocol.ResponseOK
218 self._fncache = {} 218 self._fncache = {}
219 self.dircache = [] 219 self.dircache = []
220 self.inRawMode = 0
221 self.mainProcStr = None # used for the passive mode 220 self.mainProcStr = None # used for the passive mode
222 self.passive = 0 # used to indicate the passive mode 221 self.passive = False # used to indicate the passive mode
223 self.running = None 222 self.running = None
224 self.test = None 223 self.test = None
225 self.tracePython = 0 224 self.tracePython = False
226 self.debugging = 0 225 self.debugging = False
227 226
228 self.fork_auto = False 227 self.fork_auto = False
229 self.fork_child = False 228 self.fork_child = False
230 229
231 self.readstream = None 230 self.readstream = None
331 d["broken"] = self.isBroken() 330 d["broken"] = self.isBroken()
332 else: 331 else:
333 d["broken"] = False 332 d["broken"] = False
334 threadList.append(d) 333 threadList.append(d)
335 334
336 self.write('%s%s\n' % (DebugProtocol.ResponseThreadList, 335 self.sendJsonCommand("ResponseThreadList", {
337 unicode((currentId, threadList)))) 336 "currentID": currentId,
337 "threadList": threadList,
338 })
338 339
339 def raw_input(self, prompt, echo): 340 def raw_input(self, prompt, echo):
340 """ 341 """
341 Public method to implement raw_input() using the event loop. 342 Public method to implement raw_input() using the event loop.
342 343
343 @param prompt the prompt to be shown (string) 344 @param prompt the prompt to be shown (string)
344 @param echo Flag indicating echoing of the input (boolean) 345 @param echo Flag indicating echoing of the input (boolean)
345 @return the entered string 346 @return the entered string
346 """ 347 """
347 self.write("%s%s\n" % (DebugProtocol.ResponseRaw, 348 self.sendJsonCommand("RequestRaw", {
348 unicode((prompt, echo)))) 349 "prompt": prompt,
349 self.inRawMode = 1 350 "echo": echo,
351 })
350 self.eventLoop(True) 352 self.eventLoop(True)
351 return self.rawLine 353 return self.rawLine
352 354
353 def input(self, prompt): 355 def input(self, prompt):
354 """ 356 """
357 @param prompt the prompt to be shown (string) 359 @param prompt the prompt to be shown (string)
358 @return the entered string evaluated as a Python expresion 360 @return the entered string evaluated as a Python expresion
359 """ 361 """
360 return eval(self.raw_input(prompt, 1)) 362 return eval(self.raw_input(prompt, 1))
361 363
362 def __exceptionRaised(self): 364 def sessionClose(self, exit=True):
363 """
364 Private method called in the case of an exception.
365
366 It ensures that the debug server is informed of the raised exception.
367 """
368 self.pendingResponse = DebugProtocol.ResponseException
369
370 def sessionClose(self, exit=1):
371 """ 365 """
372 Public method to close the session with the debugger and optionally 366 Public method to close the session with the debugger and optionally
373 terminate. 367 terminate.
374 368
375 @param exit flag indicating to terminate (boolean) 369 @param exit flag indicating to terminate (boolean)
377 try: 371 try:
378 self.set_quit() 372 self.set_quit()
379 except Exception: 373 except Exception:
380 pass 374 pass
381 375
382 # clean up asyncio. 376 self.debugging = False
383 self.disconnect()
384 self.debugging = 0
385 377
386 # make sure we close down our end of the socket 378 # make sure we close down our end of the socket
387 # might be overkill as normally stdin, stdout and stderr 379 # might be overkill as normally stdin, stdout and stderr
388 # SHOULD be closed on exit, but it does not hurt to do it here 380 # SHOULD be closed on exit, but it does not hurt to do it here
389 self.readstream.close(1) 381 self.readstream.close(True)
390 self.writestream.close(1) 382 self.writestream.close(True)
391 self.errorstream.close(1) 383 self.errorstream.close(True)
392 384
393 if exit: 385 if exit:
394 # Ok, go away. 386 # Ok, go away.
395 sys.exit() 387 sys.exit()
396 388
406 # Remove any newline. 398 # Remove any newline.
407 if line[-1] == '\n': 399 if line[-1] == '\n':
408 line = line[:-1] 400 line = line[:-1]
409 401
410 ## printerr(line) ##debug 402 ## printerr(line) ##debug
411 403
412 eoc = line.find('<') 404 self.handleJsonCommand(line)
413 405
414 if eoc >= 0 and line[0] == '>': 406 def handleJsonCommand(self, jsonStr):
415 # Get the command part and any argument. 407 """
416 cmd = line[:eoc + 1] 408 Public method to handle a command serialized as a JSON string.
417 arg = line[eoc + 1:] 409
418 410 @param jsonStr string containing the command received from the IDE
419 if cmd == DebugProtocol.RequestVariables: 411 @type str
420 frmnr, scope, filter = eval(arg) 412 """
421 self.__dumpVariables(int(frmnr), int(scope), filter) 413 import json
422 return 414
423 415 try:
424 if cmd == DebugProtocol.RequestVariable: 416 commandDict = json.loads(jsonStr.strip())
425 var, frmnr, scope, filter = eval(arg) 417 except json.JSONDecodeError as err:
426 self.__dumpVariable(var, int(frmnr), int(scope), filter) 418 printerr(str(err))
427 return 419 return
428 420
429 if cmd == DebugProtocol.RequestThreadList: 421 method = commandDict["method"]
430 self.__dumpThreadList() 422 params = commandDict["params"]
431 return 423
432 424 if method == "RequestVariables":
433 if cmd == DebugProtocol.RequestThreadSet: 425 self.__dumpVariables(
434 tid = eval(arg) 426 params["frameNumber"], params["scope"], params["filters"])
435 if tid in self.threads: 427
436 self.setCurrentThread(tid) 428 elif method == "RequestVariable":
437 self.write(DebugProtocol.ResponseThreadSet + '\n') 429 self.__dumpVariable(
438 stack = self.currentThread.getStack() 430 params["variable"], params["frameNumber"],
439 self.write('%s%s\n' % (DebugProtocol.ResponseStack, 431 params["scope"], params["filters"])
440 unicode(stack))) 432
441 return 433 elif method == "RequestThreadList":
442 434 self.__dumpThreadList()
443 if cmd == DebugProtocol.RequestStep: 435
444 self.currentThread.step(1) 436 elif method == "RequestThreadSet":
445 self.eventExit = 1 437 if params["threadID"] in self.threads:
446 return 438 self.setCurrentThread(params["threadID"])
447 439 self.sendJsonCommand("ResponseThreadSet", {})
448 if cmd == DebugProtocol.RequestStepOver: 440 stack = self.currentThread.getStack()
449 self.currentThread.step(0) 441 self.sendJsonCommand("ResponseStack", {
450 self.eventExit = 1 442 "stack": stack,
451 return 443 })
452 444
453 if cmd == DebugProtocol.RequestStepOut: 445 elif method == "RequestCapabilities":
454 self.currentThread.stepOut() 446 self.sendJsonCommand("ResponseCapabilities", {
455 self.eventExit = 1 447 "capabilities": self.__clientCapabilities(),
456 return 448 "clientType": "Python3"
457 449 })
458 if cmd == DebugProtocol.RequestStepQuit: 450
459 if self.passive: 451 elif method == "RequestBanner":
460 self.progTerminated(42) 452 self.sendJsonCommand("ResponseBanner", {
453 "version": "Python {0}".format(sys.version),
454 "platform": socket.gethostname(),
455 "dbgclient": self.variant,
456 })
457
458 elif method == "RequestSetFilter":
459 self.__generateFilterObjects(params["scope"], params["filter"])
460
461 elif method == "RequestCallTrace":
462 if self.debugging:
463 self.callTraceEnabled = params["enable"]
464 else:
465 self.__newCallTraceEnabled = params["enable"]
466 # remember for later
467
468 elif method == "RequestEnvironment":
469 for key, value in params["environment"].items():
470 if key.endswith("+"):
471 if key[:-1] in os.environ:
472 os.environ[key[:-1]] += value
473 else:
474 os.environ[key[:-1]] = value
461 else: 475 else:
462 self.set_quit() 476 os.environ[key] = value
463 self.eventExit = 1 477
464 return 478 elif method == "RequestLoad":
465 479 self._fncache = {}
466 if cmd == DebugProtocol.RequestContinue: 480 self.dircache = []
467 special = int(arg) 481 sys.argv = []
468 self.currentThread.go(special) 482 params["filename"] = params["filename"].encode(
469 self.eventExit = 1 483 sys.getfilesystemencoding())
470 return 484 self.__setCoding(params["filename"])
471 485 sys.argv.append(params["filename"])
472 if cmd == DebugProtocol.RequestOK: 486 sys.argv.extend(params["argv"])
473 self.write(self.pendingResponse + '\n') 487 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
474 self.pendingResponse = DebugProtocol.ResponseOK 488 if params["workdir"] == '':
475 return 489 os.chdir(sys.path[1])
476 490 else:
477 if cmd == DebugProtocol.RequestCallTrace: 491 os.chdir(params["workdir"])
478 if arg.strip().lower() == "on": 492
479 callTraceEnabled = True 493 self.running = sys.argv[0]
494 self.mainFrame = None
495 self.debugging = True
496
497 self.fork_auto = params["autofork"]
498 self.fork_child = params["forkChild"]
499
500 self.threads.clear()
501 self.attachThread(mainThread=True)
502
503 # set the system exception handling function to ensure, that
504 # we report on all unhandled exceptions
505 sys.excepthook = self.__unhandled_exception
506 self.__interceptSignals()
507
508 # clear all old breakpoints, they'll get set after we have
509 # started
510 self.mainThread.clear_all_breaks()
511
512 self.mainThread.tracePython = params["traceInterpreter"]
513
514 # This will eventually enter a local event loop.
515 self.debugMod.__dict__['__file__'] = self.running
516 sys.modules['__main__'] = self.debugMod
517 self.callTraceEnabled = self.__newCallTraceEnabled
518 res = self.mainThread.run(
519 'execfile(' + repr(self.running) + ')',
520 self.debugMod.__dict__)
521 self.progTerminated(res)
522
523 elif method == "RequestRun":
524 sys.argv = []
525 params["filename"] = params["filename"].encode(
526 sys.getfilesystemencoding())
527 self.__setCoding(params["filename"])
528 sys.argv.append(params["filename"])
529 sys.argv.extend(params["argv"])
530 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
531 if params["workdir"] == '':
532 os.chdir(sys.path[1])
533 else:
534 os.chdir(params["workdir"])
535
536 self.running = sys.argv[0]
537 self.mainFrame = None
538 self.botframe = None
539
540 self.fork_auto = params["autofork"]
541 self.fork_child = params["forkChild"]
542
543 self.threads.clear()
544 self.attachThread(mainThread=True)
545
546 # set the system exception handling function to ensure, that
547 # we report on all unhandled exceptions
548 sys.excepthook = self.__unhandled_exception
549 self.__interceptSignals()
550
551 self.mainThread.tracePython = False
552
553 self.debugMod.__dict__['__file__'] = sys.argv[0]
554 sys.modules['__main__'] = self.debugMod
555 res = 0
556 try:
557 execfile(sys.argv[0], self.debugMod.__dict__)
558 except SystemExit as exc:
559 res = exc.code
560 atexit._run_exitfuncs()
561 self.writestream.flush()
562 self.progTerminated(res)
563
564 elif method == "RequestCoverage":
565 from coverage import coverage
566 sys.argv = []
567 params["filename"] = params["filename"].encode(
568 sys.getfilesystemencoding())
569 self.__setCoding(params["filename"])
570 sys.argv.append(params["filename"])
571 sys.argv.extend(params["argv"])
572 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
573 if params["workdir"] == '':
574 os.chdir(sys.path[1])
575 else:
576 os.chdir(params["workdir"])
577
578 # set the system exception handling function to ensure, that
579 # we report on all unhandled exceptions
580 sys.excepthook = self.__unhandled_exception
581 self.__interceptSignals()
582
583 # generate a coverage object
584 self.cover = coverage(
585 auto_data=True,
586 data_file="%s.coverage" % os.path.splitext(sys.argv[0])[0])
587
588 if params["erase"]:
589 self.cover.erase()
590 sys.modules['__main__'] = self.debugMod
591 self.debugMod.__dict__['__file__'] = sys.argv[0]
592 self.running = sys.argv[0]
593 res = 0
594 self.cover.start()
595 try:
596 execfile(sys.argv[0], self.debugMod.__dict__)
597 except SystemExit as exc:
598 res = exc.code
599 atexit._run_exitfuncs()
600 self.cover.stop()
601 self.cover.save()
602 self.writestream.flush()
603 self.progTerminated(res)
604
605 elif method == "RequestProfile":
606 sys.setprofile(None)
607 import PyProfile
608 sys.argv = []
609 params["filename"] = params["filename"].encode(
610 sys.getfilesystemencoding())
611 self.__setCoding(params["filename"])
612 sys.argv.append(params["filename"])
613 sys.argv.extend(params["argv"])
614 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
615 if params["workdir"] == '':
616 os.chdir(sys.path[1])
617 else:
618 os.chdir(params["workdir"])
619
620 # set the system exception handling function to ensure, that
621 # we report on all unhandled exceptions
622 sys.excepthook = self.__unhandled_exception
623 self.__interceptSignals()
624
625 # generate a profile object
626 self.prof = PyProfile.PyProfile(sys.argv[0])
627
628 if params["erase"]:
629 self.prof.erase()
630 self.debugMod.__dict__['__file__'] = sys.argv[0]
631 sys.modules['__main__'] = self.debugMod
632 self.running = sys.argv[0]
633 res = 0
634 try:
635 self.prof.run('execfile(%r)' % sys.argv[0])
636 except SystemExit as exc:
637 res = exc.code
638 atexit._run_exitfuncs()
639 self.prof.save()
640 self.writestream.flush()
641 self.progTerminated(res)
642
643 elif method == "ExecuteStatement":
644 if self.buffer:
645 self.buffer = self.buffer + '\n' + params["statement"]
646 else:
647 self.buffer = params["statement"]
648
649 try:
650 code = self.compile_command(self.buffer, self.readstream.name)
651 except (OverflowError, SyntaxError, ValueError):
652 # Report the exception
653 sys.last_type, sys.last_value, sys.last_traceback = \
654 sys.exc_info()
655 self.sendJsonCommand("ClientOutput", {
656 "text": "".join(traceback.format_exception_only(
657 sys.last_type, sys.last_value))
658 })
659 self.buffer = ''
660 else:
661 if code is None:
662 self.sendJsonCommand("ResponseContinue", {})
663 return
480 else: 664 else:
481 callTraceEnabled = False 665 self.buffer = ''
482 if self.debugging: 666
483 self.callTraceEnabled = callTraceEnabled 667 try:
484 else: 668 if self.running is None:
485 self.__newCallTraceEnabled = callTraceEnabled 669 exec code in self.debugMod.__dict__
486 # remember for later
487 return
488
489 if cmd == DebugProtocol.RequestEnv:
490 env = eval(arg)
491 for key, value in env.items():
492 if key.endswith("+"):
493 if key[:-1] in os.environ:
494 os.environ[key[:-1]] += value
495 else: 670 else:
496 os.environ[key[:-1]] = value 671 if self.currentThread is None:
497 else: 672 # program has terminated
498 os.environ[key] = value
499 return
500
501 if cmd == DebugProtocol.RequestLoad:
502 self._fncache = {}
503 self.dircache = []
504 sys.argv = []
505 wd, fn, args, tracePython = arg.split('|')
506 fn = fn.encode(sys.getfilesystemencoding())
507 self.__setCoding(fn)
508 sys.argv.append(fn)
509 sys.argv.extend(eval(args))
510 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
511 if wd == '':
512 os.chdir(sys.path[1])
513 else:
514 os.chdir(wd)
515 tracePython = int(tracePython)
516 self.running = sys.argv[0]
517 self.mainFrame = None
518 self.inRawMode = 0
519 self.debugging = 1
520
521 self.threads.clear()
522 self.attachThread(mainThread=1)
523
524 # set the system exception handling function to ensure, that
525 # we report on all unhandled exceptions
526 sys.excepthook = self.__unhandled_exception
527 self.__interceptSignals()
528
529 # clear all old breakpoints, they'll get set after we
530 # have started
531 self.mainThread.clear_all_breaks()
532
533 self.mainThread.tracePython = tracePython
534
535 # This will eventually enter a local event loop.
536 # Note the use of backquotes to cause a repr of self.running.
537 # The need for this is on Windows os where backslash is the
538 # path separator. They will get inadvertantly stripped away
539 # during the eval causing IOErrors, if self.running is passed
540 # as a normal str.
541 self.debugMod.__dict__['__file__'] = self.running
542 sys.modules['__main__'] = self.debugMod
543 self.callTraceEnabled = self.__newCallTraceEnabled
544 res = self.mainThread.run(
545 'execfile(' + repr(self.running) + ')',
546 self.debugMod.__dict__)
547 self.progTerminated(res)
548 return
549
550 if cmd == DebugProtocol.RequestRun:
551 sys.argv = []
552 wd, fn, args = arg.split('|')
553 fn = fn.encode(sys.getfilesystemencoding())
554 self.__setCoding(fn)
555 sys.argv.append(fn)
556 sys.argv.extend(eval(args))
557 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
558 if wd == '':
559 os.chdir(sys.path[1])
560 else:
561 os.chdir(wd)
562
563 self.running = sys.argv[0]
564 self.mainFrame = None
565 self.botframe = None
566 self.inRawMode = 0
567
568 self.threads.clear()
569 self.attachThread(mainThread=1)
570
571 # set the system exception handling function to ensure, that
572 # we report on all unhandled exceptions
573 sys.excepthook = self.__unhandled_exception
574 self.__interceptSignals()
575
576 self.mainThread.tracePython = 0
577
578 self.debugMod.__dict__['__file__'] = sys.argv[0]
579 sys.modules['__main__'] = self.debugMod
580 res = 0
581 try:
582 execfile(sys.argv[0], self.debugMod.__dict__)
583 except SystemExit as exc:
584 res = exc.code
585 atexit._run_exitfuncs()
586 self.writestream.flush()
587 self.progTerminated(res)
588 return
589
590 if cmd == DebugProtocol.RequestCoverage:
591 from coverage import coverage
592 sys.argv = []
593 wd, fn, args, erase = arg.split('@@')
594 fn = fn.encode(sys.getfilesystemencoding())
595 self.__setCoding(fn)
596 sys.argv.append(fn)
597 sys.argv.extend(eval(args))
598 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
599 if wd == '':
600 os.chdir(sys.path[1])
601 else:
602 os.chdir(wd)
603
604 # set the system exception handling function to ensure, that
605 # we report on all unhandled exceptions
606 sys.excepthook = self.__unhandled_exception
607 self.__interceptSignals()
608
609 # generate a coverage object
610 self.cover = coverage(
611 auto_data=True,
612 data_file="%s.coverage" % os.path.splitext(sys.argv[0])[0])
613
614 if int(erase):
615 self.cover.erase()
616 sys.modules['__main__'] = self.debugMod
617 self.debugMod.__dict__['__file__'] = sys.argv[0]
618 self.running = sys.argv[0]
619 res = 0
620 self.cover.start()
621 try:
622 execfile(sys.argv[0], self.debugMod.__dict__)
623 except SystemExit as exc:
624 res = exc.code
625 atexit._run_exitfuncs()
626 self.cover.stop()
627 self.cover.save()
628 self.writestream.flush()
629 self.progTerminated(res)
630 return
631
632 if cmd == DebugProtocol.RequestProfile:
633 sys.setprofile(None)
634 import PyProfile
635 sys.argv = []
636 wd, fn, args, erase = arg.split('|')
637 fn = fn.encode(sys.getfilesystemencoding())
638 self.__setCoding(fn)
639 sys.argv.append(fn)
640 sys.argv.extend(eval(args))
641 sys.path = self.__getSysPath(os.path.dirname(sys.argv[0]))
642 if wd == '':
643 os.chdir(sys.path[1])
644 else:
645 os.chdir(wd)
646
647 # set the system exception handling function to ensure, that
648 # we report on all unhandled exceptions
649 sys.excepthook = self.__unhandled_exception
650 self.__interceptSignals()
651
652 # generate a profile object
653 self.prof = PyProfile.PyProfile(sys.argv[0])
654
655 if int(erase):
656 self.prof.erase()
657 self.debugMod.__dict__['__file__'] = sys.argv[0]
658 sys.modules['__main__'] = self.debugMod
659 self.running = sys.argv[0]
660 res = 0
661 try:
662 self.prof.run('execfile(%r)' % sys.argv[0])
663 except SystemExit as exc:
664 res = exc.code
665 atexit._run_exitfuncs()
666 self.prof.save()
667 self.writestream.flush()
668 self.progTerminated(res)
669 return
670
671 if cmd == DebugProtocol.RequestShutdown:
672 self.sessionClose()
673 return
674
675 if cmd == DebugProtocol.RequestBreak:
676 fn, line, temporary, set, cond = arg.split('@@')
677 fn = fn.encode(sys.getfilesystemencoding())
678 line = int(line)
679 set = int(set)
680 temporary = int(temporary)
681
682 if set:
683 if cond == 'None' or cond == '':
684 cond = None
685 else:
686 try:
687 compile(cond, '<string>', 'eval')
688 except SyntaxError:
689 self.write(
690 '%s%s,%d\n' %
691 (DebugProtocol.ResponseBPConditionError,
692 fn, line))
693 return
694 self.mainThread.set_break(fn, line, temporary, cond)
695 else:
696 self.mainThread.clear_break(fn, line)
697
698 return
699
700 if cmd == DebugProtocol.RequestBreakEnable:
701 fn, line, enable = arg.split(',')
702 fn = fn.encode(sys.getfilesystemencoding())
703 line = int(line)
704 enable = int(enable)
705
706 bp = self.mainThread.get_break(fn, line)
707 if bp is not None:
708 if enable:
709 bp.enable()
710 else:
711 bp.disable()
712
713 return
714
715 if cmd == DebugProtocol.RequestBreakIgnore:
716 fn, line, count = arg.split(',')
717 fn = fn.encode(sys.getfilesystemencoding())
718 line = int(line)
719 count = int(count)
720
721 bp = self.mainThread.get_break(fn, line)
722 if bp is not None:
723 bp.ignore = count
724
725 return
726
727 if cmd == DebugProtocol.RequestWatch:
728 cond, temporary, set = arg.split('@@')
729 set = int(set)
730 temporary = int(temporary)
731
732 if set:
733 if not cond.endswith('??created??') and \
734 not cond.endswith('??changed??'):
735 try:
736 compile(cond, '<string>', 'eval')
737 except SyntaxError:
738 self.write('%s%s\n' % (
739 DebugProtocol.ResponseWPConditionError, cond))
740 return
741 self.mainThread.set_watch(cond, temporary)
742 else:
743 self.mainThread.clear_watch(cond)
744
745 return
746
747 if cmd == DebugProtocol.RequestWatchEnable:
748 cond, enable = arg.split(',')
749 enable = int(enable)
750
751 bp = self.mainThread.get_watch(cond)
752 if bp is not None:
753 if enable:
754 bp.enable()
755 else:
756 bp.disable()
757
758 return
759
760 if cmd == DebugProtocol.RequestWatchIgnore:
761 cond, count = arg.split(',')
762 count = int(count)
763
764 bp = self.mainThread.get_watch(cond)
765 if bp is not None:
766 bp.ignore = count
767
768 return
769
770 if cmd == DebugProtocol.RequestEval:
771 try:
772 value = eval(
773 arg, self.currentThread.getCurrentFrame().f_globals,
774 self.currentThread.getFrameLocals(self.framenr))
775 self.currentThread.storeFrameLocals(self.framenr)
776 except Exception:
777 # Report the exception and the traceback
778 try:
779 type, value, tb = sys.exc_info()
780 sys.last_type = type
781 sys.last_value = value
782 sys.last_traceback = tb
783 tblist = traceback.extract_tb(tb)
784 del tblist[:1]
785 list = traceback.format_list(tblist)
786 if list:
787 list.insert(0, "Traceback (innermost last):\n")
788 list[len(list):] = \
789 traceback.format_exception_only(type, value)
790 finally:
791 tblist = tb = None
792
793 map(self.write, list)
794
795 self.write(DebugProtocol.ResponseException + '\n')
796
797 else:
798 self.write(unicode(value) + '\n')
799 self.write(DebugProtocol.ResponseOK + '\n')
800
801 return
802
803 if cmd == DebugProtocol.RequestExec:
804 _globals = self.currentThread.getCurrentFrame().f_globals
805 _locals = self.currentThread.getFrameLocals(self.framenr)
806 try:
807 code = compile(arg + '\n', '<stdin>', 'single')
808 exec code in _globals, _locals
809 self.currentThread.storeFrameLocals(self.framenr)
810 except Exception:
811 # Report the exception and the traceback
812 try:
813 type, value, tb = sys.exc_info()
814 sys.last_type = type
815 sys.last_value = value
816 sys.last_traceback = tb
817 tblist = traceback.extract_tb(tb)
818 del tblist[:1]
819 list = traceback.format_list(tblist)
820 if list:
821 list.insert(0, "Traceback (innermost last):\n")
822 list[len(list):] = \
823 traceback.format_exception_only(type, value)
824 finally:
825 tblist = tb = None
826
827 map(self.write, list)
828
829 self.write(DebugProtocol.ResponseException + '\n')
830
831 return
832
833 if cmd == DebugProtocol.RequestBanner:
834 self.write(
835 '%s%s\n' % (
836 DebugProtocol.ResponseBanner,
837 unicode(("Python %s" % sys.version,
838 socket.gethostname(),
839 self.variant))))
840 return
841
842 if cmd == DebugProtocol.RequestCapabilities:
843 self.write('%s%d, "Python2"\n' % (
844 DebugProtocol.ResponseCapabilities,
845 self.__clientCapabilities()))
846 return
847
848 if cmd == DebugProtocol.RequestCompletion:
849 self.__completionList(arg)
850 return
851
852 if cmd == DebugProtocol.RequestSetFilter:
853 scope, filterString = eval(arg)
854 self.__generateFilterObjects(int(scope), filterString)
855 return
856
857 if cmd == DebugProtocol.RequestUTPrepare:
858 fn, tn, tfn, failed, cov, covname, erase = arg.split('|')
859 fn = fn.encode(sys.getfilesystemencoding())
860 sys.path.insert(0, os.path.dirname(os.path.abspath(fn)))
861 os.chdir(sys.path[0])
862 failed = eval(failed)
863
864 # set the system exception handling function to ensure, that
865 # we report on all unhandled exceptions
866 sys.excepthook = self.__unhandled_exception
867 self.__interceptSignals()
868
869 try:
870 import unittest
871 utModule = __import__(tn)
872 try:
873 if failed:
874 self.test = unittest.defaultTestLoader\
875 .loadTestsFromNames(failed, utModule)
876 else:
877 self.test = unittest.defaultTestLoader\
878 .loadTestsFromName(tfn, utModule)
879 except AttributeError:
880 self.test = unittest.defaultTestLoader\
881 .loadTestsFromModule(utModule)
882 except Exception:
883 exc_type, exc_value, exc_tb = sys.exc_info()
884 self.write(
885 '%s%s\n' % (
886 DebugProtocol.ResponseUTPrepared,
887 unicode((0, str(exc_type), str(exc_value)))))
888 self.__exceptionRaised()
889 return
890
891 # generate a coverage object
892 if int(cov):
893 from coverage import coverage
894 self.cover = coverage(
895 auto_data=True,
896 data_file="%s.coverage" % os.path.splitext(covname)[0])
897 if int(erase):
898 self.cover.erase()
899 else:
900 self.cover = None
901
902 self.write(
903 '%s%s\n' % (
904 DebugProtocol.ResponseUTPrepared,
905 unicode((self.test.countTestCases(), "", ""))))
906 return
907
908 if cmd == DebugProtocol.RequestUTRun:
909 from DCTestResult import DCTestResult
910 self.testResult = DCTestResult(self)
911 if self.cover:
912 self.cover.start()
913 self.test.run(self.testResult)
914 if self.cover:
915 self.cover.stop()
916 self.cover.save()
917 self.write('%s\n' % DebugProtocol.ResponseUTFinished)
918 return
919
920 if cmd == DebugProtocol.RequestUTStop:
921 self.testResult.stop()
922 return
923
924 if cmd == DebugProtocol.ResponseForkTo:
925 # this results from a separate event loop
926 self.fork_child = (arg == 'child')
927 self.eventExit = 1
928 return
929
930 if cmd == DebugProtocol.RequestForkMode:
931 self.fork_auto, self.fork_child = eval(arg)
932 return
933
934 # If we are handling raw mode input then reset the mode and break out
935 # of the current event loop.
936 if self.inRawMode:
937 self.inRawMode = 0
938 self.rawLine = line
939 self.eventExit = 1
940 return
941
942 if self.buffer:
943 self.buffer = self.buffer + '\n' + line
944 else:
945 self.buffer = line
946
947 try:
948 code = self.compile_command(self.buffer, self.readstream.name)
949 except (OverflowError, SyntaxError, ValueError):
950 # Report the exception
951 sys.last_type, sys.last_value, sys.last_traceback = sys.exc_info()
952 map(self.write, traceback.format_exception_only(
953 sys.last_type, sys.last_value))
954 self.buffer = ''
955 else:
956 if code is None:
957 self.pendingResponse = DebugProtocol.ResponseContinue
958 else:
959 self.buffer = ''
960
961 try:
962 if self.running is None:
963 exec code in self.debugMod.__dict__
964 else:
965 if self.currentThread is None:
966 # program has terminated
967 self.running = None
968 _globals = self.debugMod.__dict__
969 _locals = _globals
970 else:
971 cf = self.currentThread.getCurrentFrame()
972 # program has terminated
973 if cf is None:
974 self.running = None 673 self.running = None
975 _globals = self.debugMod.__dict__ 674 _globals = self.debugMod.__dict__
976 _locals = _globals 675 _locals = _globals
977 else: 676 else:
978 frmnr = self.framenr 677 cf = self.currentThread.getCurrentFrame()
979 while cf is not None and frmnr > 0: 678 # program has terminated
980 cf = cf.f_back 679 if cf is None:
981 frmnr -= 1 680 self.running = None
982 _globals = cf.f_globals 681 _globals = self.debugMod.__dict__
983 _locals = \ 682 _locals = _globals
984 self.currentThread.getFrameLocals( 683 else:
985 self.framenr) 684 frmnr = self.framenr
986 # reset sys.stdout to our redirector (unconditionally) 685 while cf is not None and frmnr > 0:
987 if "sys" in _globals: 686 cf = cf.f_back
988 __stdout = _globals["sys"].stdout 687 frmnr -= 1
989 _globals["sys"].stdout = self.writestream 688 _globals = cf.f_globals
990 exec code in _globals, _locals 689 _locals = \
991 _globals["sys"].stdout = __stdout 690 self.currentThread.getFrameLocals(
992 elif "sys" in _locals: 691 self.framenr)
993 __stdout = _locals["sys"].stdout 692 # reset sys.stdout to our redirector
994 _locals["sys"].stdout = self.writestream 693 # (unconditionally)
995 exec code in _globals, _locals 694 if "sys" in _globals:
996 _locals["sys"].stdout = __stdout 695 __stdout = _globals["sys"].stdout
997 else: 696 _globals["sys"].stdout = self.writestream
998 exec code in _globals, _locals 697 exec code in _globals, _locals
999 698 _globals["sys"].stdout = __stdout
1000 self.currentThread.storeFrameLocals(self.framenr) 699 elif "sys" in _locals:
1001 except SystemExit, exc: 700 __stdout = _locals["sys"].stdout
1002 self.progTerminated(exc.code) 701 _locals["sys"].stdout = self.writestream
1003 except Exception: 702 exec code in _globals, _locals
1004 # Report the exception and the traceback 703 _locals["sys"].stdout = __stdout
704 else:
705 exec code in _globals, _locals
706
707 self.currentThread.storeFrameLocals(self.framenr)
708 except SystemExit, exc:
709 self.progTerminated(exc.code)
710 except Exception:
711 # Report the exception and the traceback
712 tlist = []
713 try:
714 exc_type, exc_value, exc_tb = sys.exc_info()
715 sys.last_type = exc_type
716 sys.last_value = exc_value
717 sys.last_traceback = exc_tb
718 tblist = traceback.extract_tb(exc_tb)
719 del tblist[:1]
720 tlist = traceback.format_list(tblist)
721 if tlist:
722 tlist.insert(
723 0, "Traceback (innermost last):\n")
724 tlist.extend(traceback.format_exception_only(
725 exc_type, exc_value))
726 finally:
727 tblist = exc_tb = None
728
729 self.sendJsonCommand("ClientOutput", {
730 "text": "".join(tlist)
731 })
732
733 self.sendJsonCommand("ResponseOK", {})
734
735 elif method == "RequestStep":
736 self.currentThread.step(True)
737 self.eventExit = True
738
739 elif method == "RequestStepOver":
740 self.currentThread.step(False)
741 self.eventExit = True
742
743 elif method == "RequestStepOut":
744 self.currentThread.stepOut()
745 self.eventExit = True
746
747 elif method == "RequestStepQuit":
748 if self.passive:
749 self.progTerminated(42)
750 else:
751 self.set_quit()
752 self.eventExit = True
753
754 elif method == "RequestContinue":
755 self.currentThread.go(params["special"])
756 self.eventExit = True
757
758 elif method == "RawInput":
759 # If we are handling raw mode input then break out of the current
760 # event loop.
761 self.rawLine = params["input"]
762 self.eventExit = True
763
764 elif method == "RequestBreakpoint":
765 params["filename"] = params["filename"].encode(
766 sys.getfilesystemencoding())
767 if params["setBreakpoint"]:
768 if params["condition"] in ['None', '']:
769 params["condition"] = None
770 elif params["condition"] is not None:
1005 try: 771 try:
1006 type, value, tb = sys.exc_info() 772 compile(params["condition"], '<string>', 'eval')
1007 sys.last_type = type 773 except SyntaxError:
1008 sys.last_value = value 774 self.sendJsonCommand("ResponseBPConditionError", {
1009 sys.last_traceback = tb 775 "filename": params["filename"],
1010 tblist = traceback.extract_tb(tb) 776 "line": params["line"],
1011 del tblist[:1] 777 })
1012 list = traceback.format_list(tblist) 778 return
1013 if list: 779 self.mainThread.set_break(
1014 list.insert(0, "Traceback (innermost last):\n") 780 params["filename"], params["line"], params["temporary"],
1015 list[len(list):] = \ 781 params["condition"])
1016 traceback.format_exception_only(type, value) 782 else:
1017 finally: 783 self.mainThread.clear_break(params["filename"], params["line"])
1018 tblist = tb = None 784
1019 785 elif method == "RequestBreakpointEnable":
1020 map(self.write, list) 786 params["filename"] = params["filename"].encode(
787 sys.getfilesystemencoding())
788 bp = self.mainThread.get_break(params["filename"], params["line"])
789 if bp is not None:
790 if params["enable"]:
791 bp.enable()
792 else:
793 bp.disable()
794
795
796 elif method == "RequestBreakpointIgnore":
797 params["filename"] = params["filename"].encode(
798 sys.getfilesystemencoding())
799 bp = self.mainThread.get_break(params["filename"], params["line"])
800 if bp is not None:
801 bp.ignore = params["count"]
802
803 elif method == "RequestWatch":
804 if params["setWatch"]:
805 if not params["condition"].endswith(
806 ('??created??', '??changed??')):
807 try:
808 compile(params["condition"], '<string>', 'eval')
809 except SyntaxError:
810 self.sendJsonCommand("ResponseWatchConditionError", {
811 "condition": params["condition"],
812 })
813 return
814 self.mainThread.set_watch(
815 params["condition"], params["temporary"])
816 else:
817 self.mainThread.clear_watch(params["condition"])
818
819 elif method == "RequestWatchEnable":
820 wp = self.mainThread.get_watch(params["condition"])
821 if wp is not None:
822 if params["enable"]:
823 wp.enable()
824 else:
825 wp.disable()
826
827 elif method == "RequestWatchIgnore":
828 wp = self.mainThread.get_watch(params["condition"])
829 if wp is not None:
830 wp.ignore = params["count"]
831
832 elif method == "RequestShutdown":
833 self.sessionClose()
834
835 elif method == "RequestCompletion":
836 self.__completionList(params["text"])
837
838 elif method == "RequestUTPrepare":
839 params["filename"] = params["filename"].encode(
840 sys.getfilesystemencoding())
841 sys.path.insert(
842 0, os.path.dirname(os.path.abspath(params["filename"])))
843 os.chdir(sys.path[0])
844
845 # set the system exception handling function to ensure, that
846 # we report on all unhandled exceptions
847 sys.excepthook = self.__unhandled_exception
848 self.__interceptSignals()
849
850 try:
851 import unittest
852 utModule = __import__(params["testname"])
853 try:
854 if params["failed"]:
855 self.test = unittest.defaultTestLoader\
856 .loadTestsFromNames(params["failed"], utModule)
857 else:
858 self.test = unittest.defaultTestLoader\
859 .loadTestsFromName(params["testfunctionname"],
860 utModule)
861 except AttributeError:
862 self.test = unittest.defaultTestLoader\
863 .loadTestsFromModule(utModule)
864 except Exception:
865 exc_type, exc_value, exc_tb = sys.exc_info()
866 self.sendJsonCommand("ResponseUTPrepared", {
867 "count": 0,
868 "exception": exc_type.__name__,
869 "message": str(exc_value),
870 })
871 return
872
873 # generate a coverage object
874 if params["coverage"]:
875 from coverage import coverage
876 self.cover = coverage(
877 auto_data=True,
878 data_file="%s.coverage" % \
879 os.path.splitext(params["coveragefile"])[0])
880 if params["coverageerase"]:
881 self.cover.erase()
882 else:
883 self.cover = None
884
885 self.sendJsonCommand("ResponseUTPrepared", {
886 "count": self.test.countTestCases(),
887 "exception": "",
888 "message": "",
889 })
890
891 elif method == "RequestUTRun":
892 from DCTestResult import DCTestResult
893 self.testResult = DCTestResult(self)
894 if self.cover:
895 self.cover.start()
896 self.test.run(self.testResult)
897 if self.cover:
898 self.cover.stop()
899 self.cover.save()
900 self.sendJsonCommand("ResponseUTFinished", {})
901
902 elif method == "RequestUTStop":
903 self.testResult.stop()
904
905 elif method == "ResponseForkTo":
906 # this results from a separate event loop
907 self.fork_child = (params["target"] == 'child')
908 self.eventExit = True
909
910 def sendJsonCommand(self, method, params):
911 """
912 Public method to send a single command or response to the IDE.
913
914 @param method command or response command name to be sent
915 @type str
916 @param params dictionary of named parameters for the command or
917 response
918 @type dict
919 """
920 cmd = prepareJsonCommand(method, params)
921
922 self.writestream.write_p(cmd)
923 self.writestream.flush()
924
925 def sendClearTemporaryBreakpoint(self, filename, lineno):
926 """
927 Public method to signal the deletion of a temporary breakpoint.
928
929 @param filename name of the file the bp belongs to
930 @type str
931 @param lineno linenumber of the bp
932 @type int
933 """
934 self.sendJsonCommand("ResponseClearBreakpoint", {
935 "filename": filename,
936 "line": lineno
937 })
938
939 def sendClearTemporaryWatch(self, condition):
940 """
941 Public method to signal the deletion of a temporary watch expression.
942
943 @param condition condition of the watch expression to be cleared
944 @type str
945 """
946 self.sendJsonCommand("ResponseClearWatch", {
947 "condition": condition,
948 })
949
950 def sendResponseLine(self, stack):
951 """
952 Public method to send the current call stack.
953
954 @param stack call stack
955 @type list
956 """
957 self.sendJsonCommand("ResponseLine", {
958 "stack": stack,
959 })
960
961 def sendCallTrace(self, event, fromStr, toStr):
962 """
963 Public method to send a call trace entry.
964
965 @param event trace event (call or return)
966 @type str
967 @param fromStr pre-formatted origin info
968 @type str
969 @param toStr pre-formatted target info
970 @type str
971 """
972 self.sendJsonCommand("CallTrace", {
973 "event": event[0],
974 "from": fromStr,
975 "to": toStr,
976 })
977
978 def sendException(self, exceptionType, exceptionMessage, stack):
979 """
980 Public method to send information for an exception.
981
982 @param exceptionType type of exception raised
983 @type str
984 @param exceptionMessage message of the exception
985 @type str
986 @param stack stack trace information
987 @type list
988 """
989 self.sendJsonCommand("ResponseException", {
990 "type": exceptionType,
991 "message": exceptionMessage,
992 "stack": stack,
993 })
994
995 def sendSyntaxError(self, message, filename, lineno, charno):
996 """
997 Public method to send information for a syntax error.
998
999 @param message syntax error message
1000 @type str
1001 @param filename name of the faulty file
1002 @type str
1003 @param lineno line number info
1004 @type int
1005 @param charno character number info
1006 @tyoe int
1007 """
1008 self.sendJsonCommand("ResponseSyntax", {
1009 "message": message,
1010 "filename": filename,
1011 "linenumber": lineno,
1012 "characternumber": charno,
1013 })
1014
1015 def sendPassiveStartup(self, filename, exceptions):
1016 """
1017 Public method to send the passive start information.
1018
1019 @param filename name of the script
1020 @type str
1021 @param exceptions flag to enable exception reporting of the IDE
1022 @type bool
1023 """
1024 self.sendJsonCommand("PassiveStartup", {
1025 "filename": filename,
1026 "exceptions": exceptions,
1027 })
1021 1028
1022 def __clientCapabilities(self): 1029 def __clientCapabilities(self):
1023 """ 1030 """
1024 Private method to determine the clients capabilities. 1031 Private method to determine the clients capabilities.
1025 1032
1033 pass 1040 pass
1034 return self.clientCapabilities 1041 return self.clientCapabilities
1035 except ImportError: 1042 except ImportError:
1036 return ( 1043 return (
1037 self.clientCapabilities & ~DebugClientCapabilities.HasProfiler) 1044 self.clientCapabilities & ~DebugClientCapabilities.HasProfiler)
1038 1045
1039 def write(self, s): 1046 def readReady(self, stream):
1040 """ 1047 """
1041 Public method to write data to the output stream. 1048 Public method called when there is data ready to be read.
1042 1049
1043 @param s data to be written (string) 1050 @param stream file like object that has data to be written
1044 """ 1051 """
1045 self.writestream.write(s) 1052 try:
1046 self.writestream.flush() 1053 got = stream.readline_p()
1054 except Exception:
1055 return
1056
1057 if len(got) == 0:
1058 self.sessionClose()
1059 return
1060
1061 self.__receiveBuffer = self.__receiveBuffer + got
1062
1063 # Call handleLine for the line if it is complete.
1064 eol = self.__receiveBuffer.find('\n')
1065 while eol >= 0:
1066 line = self.__receiveBuffer[:eol + 1]
1067 self.__receiveBuffer = self.__receiveBuffer[eol + 1:]
1068 self.handleLine(line)
1069 eol = self.__receiveBuffer.find('\n')
1070
1071 def writeReady(self, stream):
1072 """
1073 Public method called when we are ready to write data.
1074
1075 @param stream file like object that has data to be written
1076 """
1077 stream.write_p("")
1078 stream.flush()
1047 1079
1048 def __interact(self): 1080 def __interact(self):
1049 """ 1081 """
1050 Private method to interact with the debugger. 1082 Private method to interact with the debugger.
1051 """ 1083 """
1052 global DebugClientInstance 1084 global DebugClientInstance
1053 1085
1054 self.setDescriptors(self.readstream, self.writestream)
1055 DebugClientInstance = self 1086 DebugClientInstance = self
1087 self.__receiveBuffer = ""
1056 1088
1057 if not self.passive: 1089 if not self.passive:
1058 # At this point simulate an event loop. 1090 # At this point simulate an event loop.
1059 self.eventLoop() 1091 self.eventLoop()
1060 1092
1085 except (select.error, KeyboardInterrupt, socket.error): 1117 except (select.error, KeyboardInterrupt, socket.error):
1086 # just carry on 1118 # just carry on
1087 continue 1119 continue
1088 1120
1089 if self.readstream in rrdy: 1121 if self.readstream in rrdy:
1090 self.readReady(self.readstream.fileno()) 1122 self.readReady(self.readstream)
1091 1123
1092 if self.writestream in wrdy: 1124 if self.writestream in wrdy:
1093 self.writeReady(self.writestream.fileno()) 1125 self.writeReady(self.writestream)
1094 1126
1095 if self.errorstream in wrdy: 1127 if self.errorstream in wrdy:
1096 self.writeReady(self.errorstream.fileno()) 1128 self.writeReady(self.errorstream)
1097 1129
1098 self.eventExit = None 1130 self.eventExit = None
1099 self.pollingDisabled = False 1131 self.pollingDisabled = False
1100 1132
1101 def eventPoll(self): 1133 def eventPoll(self):
1126 rrdy, wrdy, xrdy = select.select([self.readstream], wrdy, [], 0) 1158 rrdy, wrdy, xrdy = select.select([self.readstream], wrdy, [], 0)
1127 except (select.error, KeyboardInterrupt, socket.error): 1159 except (select.error, KeyboardInterrupt, socket.error):
1128 return 1160 return
1129 1161
1130 if self.readstream in rrdy: 1162 if self.readstream in rrdy:
1131 self.readReady(self.readstream.fileno()) 1163 self.readReady(self.readstream)
1132 1164
1133 if self.writestream in wrdy: 1165 if self.writestream in wrdy:
1134 self.writeReady(self.writestream.fileno()) 1166 self.writeReady(self.writestream)
1135 1167
1136 if self.errorstream in wrdy: 1168 if self.errorstream in wrdy:
1137 self.writeReady(self.errorstream.fileno()) 1169 self.writeReady(self.errorstream)
1138 1170
1139 def connectDebugger(self, port, remoteAddress=None, redirect=1): 1171 def connectDebugger(self, port, remoteAddress=None, redirect=1):
1140 """ 1172 """
1141 Public method to establish a session with the debugger. 1173 Public method to establish a session with the debugger.
1142 1174
1175 1207
1176 @param exctype the type of the exception 1208 @param exctype the type of the exception
1177 @param excval data about the exception 1209 @param excval data about the exception
1178 @param exctb traceback for the exception 1210 @param exctb traceback for the exception
1179 """ 1211 """
1180 self.mainThread.user_exception(None, (exctype, excval, exctb), 1) 1212 self.mainThread.user_exception(None, (exctype, excval, exctb), True)
1181 1213
1182 def __interceptSignals(self): 1214 def __interceptSignals(self):
1183 """ 1215 """
1184 Private method to intercept common signals. 1216 Private method to intercept common signals.
1185 """ 1217 """
1228 except Exception: 1260 except Exception:
1229 fargs = "" 1261 fargs = ""
1230 else: 1262 else:
1231 fargs = "" 1263 fargs = ""
1232 1264
1233 siglist = [message, [filename, linenr, ffunc, fargs]] 1265 self.sendJsonCommand("ResponseSignal", {
1234 1266 "message": message,
1235 self.write("%s%s" % (DebugProtocol.ResponseSignal, str(siglist))) 1267 "filename": filename,
1236 1268 "linenumber": linenr,
1269 "function": ffunc,
1270 "arguments": fargs,
1271 })
1272
1237 def absPath(self, fn): 1273 def absPath(self, fn):
1238 """ 1274 """
1239 Public method to convert a filename to an absolute name. 1275 Public method to convert a filename to an absolute name.
1240 1276
1241 sys.path is used as a set of possible prefixes. The name stays 1277 sys.path is used as a set of possible prefixes. The name stays
1282 @param fn filename to be checked 1318 @param fn filename to be checked
1283 @return non-zero if fn represents a file we are 'skipping', 1319 @return non-zero if fn represents a file we are 'skipping',
1284 zero otherwise. 1320 zero otherwise.
1285 """ 1321 """
1286 if self.mainThread.tracePython: # trace into Python library 1322 if self.mainThread.tracePython: # trace into Python library
1287 return 0 1323 return False
1288 1324
1289 # Eliminate anything that is part of the Python installation. 1325 # Eliminate anything that is part of the Python installation.
1290 afn = self.absPath(fn) 1326 afn = self.absPath(fn)
1291 for d in self.skipdirs: 1327 for d in self.skipdirs:
1292 if afn.startswith(d): 1328 if afn.startswith(d):
1293 return 1 1329 return True
1294 1330
1295 # special treatment for paths containing site-packages or dist-packages 1331 # special treatment for paths containing site-packages or dist-packages
1296 for part in ["site-packages", "dist-packages"]: 1332 for part in ["site-packages", "dist-packages"]:
1297 if part in afn: 1333 if part in afn:
1298 return 1 1334 return True
1299 1335
1300 return 0 1336 return False
1301 1337
1302 def getRunning(self): 1338 def getRunning(self):
1303 """ 1339 """
1304 Public method to return the main script we are currently running. 1340 Public method to return the main script we are currently running.
1305 1341
1306 @return flag indicating a running debug session (boolean) 1342 @return flag indicating a running debug session (boolean)
1307 """ 1343 """
1308 return self.running 1344 return self.running
1309 1345
1310 def progTerminated(self, status): 1346 def progTerminated(self, status, message=""):
1311 """ 1347 """
1312 Public method to tell the debugger that the program has terminated. 1348 Public method to tell the debugger that the program has terminated.
1313 1349
1314 @param status return status 1350 @param status return status
1315 @type int 1351 @type int
1352 @param message status message
1353 @type str
1316 """ 1354 """
1317 if status is None: 1355 if status is None:
1318 status = 0 1356 status = 0
1319 else: 1357 elif not isinstance(status, int):
1320 try: 1358 message = str(status)
1321 int(status) 1359 status = 1
1322 except ValueError:
1323 status = 1
1324 1360
1325 if self.running: 1361 if self.running:
1326 self.set_quit() 1362 self.set_quit()
1327 self.running = None 1363 self.running = None
1328 self.write('%s%d\n' % (DebugProtocol.ResponseExit, status)) 1364 self.sendJsonCommand("ResponseExit", {
1365 "status": status,
1366 "message": message,
1367 })
1329 1368
1330 # reset coding 1369 # reset coding
1331 self.__coding = self.defaultCoding 1370 self.__coding = self.defaultCoding
1332 1371
1333 def __dumpVariables(self, frmnr, scope, filter): 1372 def __dumpVariables(self, frmnr, scope, filter):
1362 elif f.f_globals is f.f_locals: 1401 elif f.f_globals is f.f_locals:
1363 scope = -1 1402 scope = -1
1364 else: 1403 else:
1365 dict = f.f_locals 1404 dict = f.f_locals
1366 1405
1367 varlist = [scope] 1406 varlist = []
1368 1407
1369 if scope != -1: 1408 if scope != -1:
1370 keylist = dict.keys() 1409 keylist = dict.keys()
1371 1410
1372 vlist = self.__formatVariablesList(keylist, dict, scope, filter) 1411 vlist = self.__formatVariablesList(keylist, dict, scope, filter)
1373 varlist.extend(vlist) 1412 varlist.extend(vlist)
1374 1413
1375 self.write('%s%s\n' % ( 1414 self.sendJsonCommand("ResponseVariables", {
1376 DebugProtocol.ResponseVariables, unicode(varlist))) 1415 "scope": scope,
1416 "variables": varlist,
1417 })
1377 1418
1378 def __dumpVariable(self, var, frmnr, scope, filter): 1419 def __dumpVariable(self, var, frmnr, scope, filter):
1379 """ 1420 """
1380 Private method to return the variables of a frame to the debug server. 1421 Private method to return the variables of a frame to the debug server.
1381 1422
1406 elif f.f_globals is f.f_locals: 1447 elif f.f_globals is f.f_locals:
1407 scope = -1 1448 scope = -1
1408 else: 1449 else:
1409 dict = f.f_locals 1450 dict = f.f_locals
1410 1451
1411 varlist = [scope, var] 1452 varlist = []
1412 1453
1413 if scope != -1: 1454 if scope != -1:
1414 # search the correct dictionary 1455 # search the correct dictionary
1415 i = 0 1456 i = 0
1416 rvar = var[:] 1457 rvar = var[:]
1417 dictkeys = None 1458 dictkeys = None
1418 obj = None 1459 obj = None
1419 isDict = 0 1460 isDict = False
1420 formatSequences = 0 1461 formatSequences = False
1421 access = "" 1462 access = ""
1422 oaccess = "" 1463 oaccess = ""
1423 odict = dict 1464 odict = dict
1424 1465
1425 qtVariable = False 1466 qtVariable = False
1435 if i + 1 == len(var): 1476 if i + 1 == len(var):
1436 if var[i][:-2] == '...': 1477 if var[i][:-2] == '...':
1437 dictkeys = [var[i - 1]] 1478 dictkeys = [var[i - 1]]
1438 else: 1479 else:
1439 dictkeys = [var[i][:-2]] 1480 dictkeys = [var[i][:-2]]
1440 formatSequences = 1 1481 formatSequences = True
1441 if not access and not oaccess: 1482 if not access and not oaccess:
1442 if var[i][:-2] == '...': 1483 if var[i][:-2] == '...':
1443 access = '["%s"]' % var[i - 1] 1484 access = '["%s"]' % var[i - 1]
1444 dict = odict 1485 dict = odict
1445 else: 1486 else:
1456 access = '%s[%s]' % (oaccess, var[i][:-2]) 1497 access = '%s[%s]' % (oaccess, var[i][:-2])
1457 oaccess = '' 1498 oaccess = ''
1458 else: 1499 else:
1459 access = '%s[%s]' % (access, var[i][:-2]) 1500 access = '%s[%s]' % (access, var[i][:-2])
1460 if var[i][-2:] == "{}": # __IGNORE_WARNING__ 1501 if var[i][-2:] == "{}": # __IGNORE_WARNING__
1461 isDict = 1 1502 isDict = True
1462 break 1503 break
1463 else: 1504 else:
1464 if not access: 1505 if not access:
1465 if var[i][:-2] == '...': 1506 if var[i][:-2] == '...':
1466 access = '["%s"]' % var[i - 1] 1507 access = '["%s"]' % var[i - 1]
1621 elif unicode(repr(obj)).startswith('('): 1662 elif unicode(repr(obj)).startswith('('):
1622 varlist.append(('...', 'tuple', "%d" % len(obj))) 1663 varlist.append(('...', 'tuple', "%d" % len(obj)))
1623 except Exception: 1664 except Exception:
1624 pass 1665 pass
1625 1666
1626 self.write('%s%s\n' % ( 1667 self.sendJsonCommand("ResponseVariable", {
1627 DebugProtocol.ResponseVariable, unicode(varlist))) 1668 "scope": scope,
1669 "variable": var,
1670 "variables": varlist,
1671 })
1628 1672
1629 def __formatQtVariable(self, value, vtype): 1673 def __formatQtVariable(self, value, vtype):
1630 """ 1674 """
1631 Private method to produce a formated output of a simple Qt4/Qt5 type. 1675 Private method to produce a formated output of a simple Qt4/Qt5 type.
1632 1676
1791 else: 1835 else:
1792 patternFilterObjects = self.localsFilterObjects 1836 patternFilterObjects = self.localsFilterObjects
1793 1837
1794 for key in keylist: 1838 for key in keylist:
1795 # filter based on the filter pattern 1839 # filter based on the filter pattern
1796 matched = 0 1840 matched = False
1797 for pat in patternFilterObjects: 1841 for pat in patternFilterObjects:
1798 if pat.match(unicode(key)): 1842 if pat.match(unicode(key)):
1799 matched = 1 1843 matched = True
1800 break 1844 break
1801 if matched: 1845 if matched:
1802 continue 1846 continue
1803 1847
1804 # filter hidden attributes (filter #0) 1848 # filter hidden attributes (filter #0)
1905 self.__getCompletionList(text, localCompleter, completions) 1949 self.__getCompletionList(text, localCompleter, completions)
1906 except AttributeError: 1950 except AttributeError:
1907 pass 1951 pass
1908 self.__getCompletionList(text, self.complete, completions) 1952 self.__getCompletionList(text, self.complete, completions)
1909 1953
1910 self.write("%s%s||%s\n" % (DebugProtocol.ResponseCompletion, 1954 self.sendJsonCommand("ResponseCompletion", {
1911 unicode(list(completions)), text)) 1955 "completions": list(completions),
1956 "text": text,
1957 })
1912 1958
1913 def __getCompletionList(self, text, completer, completions): 1959 def __getCompletionList(self, text, completer, completions):
1914 """ 1960 """
1915 Private method to create a completions list. 1961 Private method to create a completions list.
1916 1962
1930 comp = completer(text, state) 1976 comp = completer(text, state)
1931 except Exception: 1977 except Exception:
1932 comp = None 1978 comp = None
1933 1979
1934 def startDebugger(self, filename=None, host=None, port=None, 1980 def startDebugger(self, filename=None, host=None, port=None,
1935 enableTrace=1, exceptions=1, tracePython=0, redirect=1): 1981 enableTrace=True, exceptions=True, tracePython=False,
1982 redirect=True):
1936 """ 1983 """
1937 Public method used to start the remote debugger. 1984 Public method used to start the remote debugger.
1938 1985
1939 @param filename the program to be debugged (string) 1986 @param filename the program to be debugged (string)
1940 @param host hostname of the debug server (string) 1987 @param host hostname of the debug server (string)
1962 self.running = os.path.abspath(sys.argv[0]) 2009 self.running = os.path.abspath(sys.argv[0])
1963 except IndexError: 2010 except IndexError:
1964 self.running = None 2011 self.running = None
1965 if self.running: 2012 if self.running:
1966 self.__setCoding(self.running) 2013 self.__setCoding(self.running)
1967 self.passive = 1 2014 self.passive = True
1968 self.write("%s%s|%d\n" % ( 2015 self.sendPassiveStartup(self.running, exceptions)
1969 DebugProtocol.PassiveStartup, self.running, exceptions))
1970 self.__interact() 2016 self.__interact()
1971 2017
1972 # setup the debugger variables 2018 # setup the debugger variables
1973 self._fncache = {} 2019 self._fncache = {}
1974 self.dircache = [] 2020 self.dircache = []
1975 self.mainFrame = None 2021 self.mainFrame = None
1976 self.inRawMode = 0 2022 self.debugging = True
1977 self.debugging = 1 2023
1978 2024 self.attachThread(mainThread=True)
1979 self.attachThread(mainThread=1)
1980 self.mainThread.tracePython = tracePython 2025 self.mainThread.tracePython = tracePython
1981 2026
1982 # set the system exception handling function to ensure, that 2027 # set the system exception handling function to ensure, that
1983 # we report on all unhandled exceptions 2028 # we report on all unhandled exceptions
1984 sys.excepthook = self.__unhandled_exception 2029 sys.excepthook = self.__unhandled_exception
1987 # now start debugging 2032 # now start debugging
1988 if enableTrace: 2033 if enableTrace:
1989 self.mainThread.set_trace() 2034 self.mainThread.set_trace()
1990 2035
1991 def startProgInDebugger(self, progargs, wd='', host=None, 2036 def startProgInDebugger(self, progargs, wd='', host=None,
1992 port=None, exceptions=1, tracePython=0, 2037 port=None, exceptions=True, tracePython=False,
1993 redirect=1): 2038 redirect=True):
1994 """ 2039 """
1995 Public method used to start the remote debugger. 2040 Public method used to start the remote debugger.
1996 2041
1997 @param progargs commandline for the program to be debugged 2042 @param progargs commandline for the program to be debugged
1998 (list of strings) 2043 (list of strings)
2024 else: 2069 else:
2025 os.chdir(wd) 2070 os.chdir(wd)
2026 self.running = sys.argv[0] 2071 self.running = sys.argv[0]
2027 self.__setCoding(self.running) 2072 self.__setCoding(self.running)
2028 self.mainFrame = None 2073 self.mainFrame = None
2029 self.inRawMode = 0 2074 self.debugging = True
2030 self.debugging = 1 2075
2031 2076 self.passive = True
2032 self.passive = 1 2077 self.sendPassiveStartup(self.running, exceptions)
2033 self.write("%s%s|%d\n" % (
2034 DebugProtocol.PassiveStartup, self.running, exceptions))
2035 self.__interact() 2078 self.__interact()
2036 2079
2037 self.attachThread(mainThread=1) 2080 self.attachThread(mainThread=1)
2038 self.mainThread.tracePython = tracePython 2081 self.mainThread.tracePython = tracePython
2039 2082
2092 if '--' in sys.argv: 2135 if '--' in sys.argv:
2093 args = sys.argv[1:] 2136 args = sys.argv[1:]
2094 host = None 2137 host = None
2095 port = None 2138 port = None
2096 wd = '' 2139 wd = ''
2097 tracePython = 0 2140 tracePython = False
2098 exceptions = 1 2141 exceptions = True
2099 redirect = 1 2142 redirect = True
2100 while args[0]: 2143 while args[0]:
2101 if args[0] == '-h': 2144 if args[0] == '-h':
2102 host = args[1] 2145 host = args[1]
2103 del args[0] 2146 del args[0]
2104 del args[0] 2147 del args[0]
2109 elif args[0] == '-w': 2152 elif args[0] == '-w':
2110 wd = args[1] 2153 wd = args[1]
2111 del args[0] 2154 del args[0]
2112 del args[0] 2155 del args[0]
2113 elif args[0] == '-t': 2156 elif args[0] == '-t':
2114 tracePython = 1 2157 tracePython = True
2115 del args[0] 2158 del args[0]
2116 elif args[0] == '-e': 2159 elif args[0] == '-e':
2117 exceptions = 0 2160 exceptions = False
2118 del args[0] 2161 del args[0]
2119 elif args[0] == '-n': 2162 elif args[0] == '-n':
2120 redirect = 0 2163 redirect = False
2121 del args[0] 2164 del args[0]
2122 elif args[0] == '--no-encoding': 2165 elif args[0] == '--no-encoding':
2123 self.noencoding = True 2166 self.noencoding = True
2124 del args[0] 2167 del args[0]
2125 elif args[0] == '--fork-child': 2168 elif args[0] == '--fork-child':
2155 except (ValueError, IndexError): 2198 except (ValueError, IndexError):
2156 port = -1 2199 port = -1
2157 try: 2200 try:
2158 redirect = int(sys.argv[2]) 2201 redirect = int(sys.argv[2])
2159 except (ValueError, IndexError): 2202 except (ValueError, IndexError):
2160 redirect = 1 2203 redirect = True
2161 try: 2204 try:
2162 ipOrHost = sys.argv[3] 2205 ipOrHost = sys.argv[3]
2163 if ':' in ipOrHost: 2206 if ':' in ipOrHost:
2164 remoteAddress = ipOrHost 2207 remoteAddress = ipOrHost
2165 elif ipOrHost[0] in '0123456789': 2208 elif ipOrHost[0] in '0123456789':
2185 follow. 2228 follow.
2186 2229
2187 @return process ID (integer) 2230 @return process ID (integer)
2188 """ 2231 """
2189 if not self.fork_auto: 2232 if not self.fork_auto:
2190 self.write(DebugProtocol.RequestForkTo + '\n') 2233 self.sendJsonCommand("RequestForkTo", {})
2191 self.eventLoop(True) 2234 self.eventLoop(True)
2192 pid = DebugClientOrigFork() 2235 pid = DebugClientOrigFork()
2193 if pid == 0: 2236 if pid == 0:
2194 # child 2237 # child
2195 if not self.fork_child: 2238 if not self.fork_child:

eric ide

mercurial