325 # No need to trace this function |
325 # No need to trace this function |
326 return |
326 return |
327 return self.trace_dispatch |
327 return self.trace_dispatch |
328 |
328 |
329 if event == 'return': |
329 if event == 'return': |
330 if self.stop_here(frame) or frame == self.botframe: |
|
331 # Ignore return events in generator except when stepping. |
|
332 if self.stopframe and frame.f_code.co_flags & CO_GENERATOR: |
|
333 return |
|
334 # The program has finished if we have just left the first frame |
|
335 if frame == self.botframe: |
|
336 if self.isMainThread: |
|
337 atexit._run_exitfuncs() |
|
338 self._dbgClient.progTerminated(arg) |
|
339 else: |
|
340 self._dbgClient.threadTerminated(self.id) |
|
341 |
|
342 if self.quitting and not self._dbgClient.passive: |
|
343 raise SystemExit |
|
344 return |
330 return |
345 |
331 |
346 if event == 'exception': |
332 if event == 'exception': |
347 if not self.__skipFrame(frame): |
333 if not self.__skipFrame(frame): |
348 # When stepping with next/until/return in a generator frame, |
334 # When stepping with next/until/return in a generator frame, |
462 if not isinstance(cmd, types.CodeType): |
448 if not isinstance(cmd, types.CodeType): |
463 cmd = compile(cmd, "<string>", "exec") |
449 cmd = compile(cmd, "<string>", "exec") |
464 |
450 |
465 try: |
451 try: |
466 exec(cmd, globals, locals) |
452 exec(cmd, globals, locals) |
|
453 atexit._run_exitfuncs() |
|
454 self._dbgClient.progTerminated(0) |
467 except SystemExit: |
455 except SystemExit: |
468 pass |
456 atexit._run_exitfuncs() |
|
457 excinfo = sys.exc_info() |
|
458 exitcode, message = self.__extractSystemExitMessage(excinfo) |
|
459 self._dbgClient.progTerminated(exitcode, message) |
469 finally: |
460 finally: |
470 self.quitting = True |
461 self.quitting = True |
471 sys.settrace(None) |
462 sys.settrace(None) |
472 |
463 |
473 def _set_stopinfo(self, stopframe, returnframe): |
464 def _set_stopinfo(self, stopframe, returnframe): |
776 @keyparam unhandled flag indicating an uncaught exception |
767 @keyparam unhandled flag indicating an uncaught exception |
777 @type bool |
768 @type bool |
778 """ |
769 """ |
779 exctype, excval, exctb = excinfo |
770 exctype, excval, exctb = excinfo |
780 |
771 |
781 if exctype in [GeneratorExit, StopIteration]: |
772 if exctype in [GeneratorExit, StopIteration, SystemExit]: |
782 # ignore these |
773 # ignore these |
783 return |
|
784 |
|
785 if exctype == SystemExit: |
|
786 atexit._run_exitfuncs() |
|
787 if excval is None: |
|
788 exitcode = 0 |
|
789 message = "" |
|
790 elif isinstance(excval, basestring): |
|
791 exitcode = 1 |
|
792 message = excval |
|
793 elif isinstance(excval, bytes): |
|
794 exitcode = 1 |
|
795 message = excval.decode() |
|
796 elif isinstance(excval, int): |
|
797 exitcode = excval |
|
798 message = "" |
|
799 elif isinstance(excval, SystemExit): |
|
800 code = excval.code |
|
801 if isinstance(code, basestring): |
|
802 exitcode = 1 |
|
803 message = code |
|
804 elif isinstance(code, bytes): |
|
805 exitcode = 1 |
|
806 message = code.decode() |
|
807 elif isinstance(code, int): |
|
808 exitcode = code |
|
809 message = "" |
|
810 else: |
|
811 exitcode = 1 |
|
812 message = str(code) |
|
813 else: |
|
814 exitcode = 1 |
|
815 message = str(excval) |
|
816 self._dbgClient.progTerminated(exitcode, message) |
|
817 return |
774 return |
818 |
775 |
819 if exctype in [SyntaxError, IndentationError]: |
776 if exctype in [SyntaxError, IndentationError]: |
820 try: |
777 try: |
821 # tuple could only occure on Python 2, but not always! |
778 # tuple could only occure on Python 2, but not always! |
930 stack.append(tb.tb_frame) |
887 stack.append(tb.tb_frame) |
931 tb = tb.tb_next |
888 tb = tb.tb_next |
932 tb = None |
889 tb = None |
933 return stack |
890 return stack |
934 |
891 |
|
892 def __extractSystemExitMessage(self, excinfo): |
|
893 """ |
|
894 Private method to get the SystemExit code and message. |
|
895 |
|
896 @param excinfo details about the SystemExit exception |
|
897 @type tuple(Exception, excval object, traceback frame object) |
|
898 @return SystemExit code and message |
|
899 @rtype int, str |
|
900 """ |
|
901 exctype, excval, exctb = excinfo |
|
902 if excval is None: |
|
903 exitcode = 0 |
|
904 message = "" |
|
905 elif isinstance(excval, basestring): |
|
906 exitcode = 1 |
|
907 message = excval |
|
908 elif isinstance(excval, bytes): |
|
909 exitcode = 1 |
|
910 message = excval.decode() |
|
911 elif isinstance(excval, int): |
|
912 exitcode = excval |
|
913 message = "" |
|
914 elif isinstance(excval, SystemExit): |
|
915 code = excval.code |
|
916 if isinstance(code, basestring): |
|
917 exitcode = 1 |
|
918 message = code |
|
919 elif isinstance(code, bytes): |
|
920 exitcode = 1 |
|
921 message = code.decode() |
|
922 elif isinstance(code, int): |
|
923 exitcode = code |
|
924 message = "" |
|
925 else: |
|
926 exitcode = 1 |
|
927 message = str(code) |
|
928 else: |
|
929 exitcode = 1 |
|
930 message = str(excval) |
|
931 |
|
932 return exitcode, message |
|
933 |
935 def stop_here(self, frame): |
934 def stop_here(self, frame): |
936 """ |
935 """ |
937 Public method reimplemented to filter out debugger files. |
936 Public method reimplemented to filter out debugger files. |
938 |
937 |
939 Tracing is turned off for files that are part of the |
938 Tracing is turned off for files that are part of the |