Merged with changes done by Tobias.

Mon, 20 Feb 2017 19:32:48 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Mon, 20 Feb 2017 19:32:48 +0100
changeset 5541
0498dc01d58c
parent 5534
f9368ecf153a (current diff)
parent 5540
40992b7a60a9 (diff)
child 5542
520713d0a381

Merged with changes done by Tobias.

--- a/DebugClients/Python/BreakpointWatch.py	Mon Feb 20 19:27:37 2017 +0100
+++ b/DebugClients/Python/BreakpointWatch.py	Mon Feb 20 19:32:48 2017 +0100
@@ -50,21 +50,21 @@
         self.enabled = True
         self.ignore = 0
         self.hits = 0
-        self.breaks[filename, lineno] = self
-        lines = self.breakInFile.setdefault(filename, [])
+        Breakpoint.breaks[(filename, lineno)] = self
+        lines = Breakpoint.breakInFile.setdefault(filename, [])
         if lineno not in lines:
             lines.append(lineno)
-        self.breakInFrameCache.clear()
+        Breakpoint.breakInFrameCache.clear()
 
     def deleteMe(self):
         """
         Public method to clear this breakpoint.
         """
         try:
-            del self.breaks[(self.file, self.line)]
-            self.breakInFile[self.file].remove(self.line)
-            if not self.breakInFile[self.file]:
-                del self.breakInFile[self.file]
+            del Breakpoint.breaks[(self.file, self.line)]
+            Breakpoint.breakInFile[self.file].remove(self.line)
+            if not Breakpoint.breakInFile[self.file]:
+                del Breakpoint.breakInFile[self.file]
         except KeyError:
             pass
 
@@ -100,8 +100,8 @@
         """
         Public method to clear all breakpoints.
         """
-        for bp in Breakpoint.breaks.copy():
-            bp.deleteMe()
+        Breakpoint.breaks.clear()
+        Breakpoint.breakInFile.clear()
         Breakpoint.breakInFrameCache.clear()
 
     @staticmethod
@@ -222,14 +222,14 @@
             self.changed = True
         
         self.values = {}
-        self.watches.append(self)
+        Watch.watches.append(self)
 
     def deleteMe(self):
         """
         Public method to clear this watch expression.
         """
         try:
-            del self.watches[self]
+            del Watch.watches[self]
         except ValueError:
             pass
 
--- a/DebugClients/Python/DebugBase.py	Mon Feb 20 19:27:37 2017 +0100
+++ b/DebugClients/Python/DebugBase.py	Mon Feb 20 19:32:48 2017 +0100
@@ -327,20 +327,6 @@
             return self.trace_dispatch
         
         if event == 'return':
-            if self.stop_here(frame) or frame == self.botframe:
-                # Ignore return events in generator except when stepping.
-                if self.stopframe and frame.f_code.co_flags & CO_GENERATOR:
-                    return
-                # The program has finished if we have just left the first frame
-                if frame == self.botframe:
-                    if self.isMainThread:
-                        atexit._run_exitfuncs()
-                        self._dbgClient.progTerminated(arg)
-                    else:
-                        self._dbgClient.threadTerminated(self.id)
-                
-                if self.quitting and not self._dbgClient.passive:
-                    raise SystemExit
             return
         
         if event == 'exception':
@@ -351,7 +337,7 @@
                 # statement.
                 if not (frame.f_code.co_flags & CO_GENERATOR and
                         arg[0] is StopIteration and arg[2] is None):
-                    self.user_exception(frame, arg)
+                    self.user_exception(arg)
             # Stop at the StopIteration or GeneratorExit exception when the
             # user has set stopframe in a generator by issuing a return
             # command, or a next/until command at the last statement in the
@@ -359,7 +345,7 @@
             elif (self.stopframe and frame is not self.stopframe and
                     self.stopframe.f_code.co_flags & CO_GENERATOR and
                     arg[0] in (StopIteration, GeneratorExit)):
-                self.user_exception(frame, arg)
+                self.user_exception(arg)
             return
 
         if event == 'c_call':
@@ -435,12 +421,14 @@
             frame.f_trace = self.trace_dispatch
             
             target(*args, **kwargs)
-        except SystemExit:
-            pass
+        except Exception:
+            excinfo = sys.exc_info()
+            self.user_exception(excinfo, True)
         finally:
+            sys.settrace(None)
             sys.setprofile(None)
     
-    def run(self, cmd, globals=None, locals=None):
+    def run(self, cmd, globals=None, locals=None, debug=True):
         """
         Public method to start a given command under debugger control.
         
@@ -458,14 +446,24 @@
         if locals is None:
             locals = globals
         
-        sys.settrace(self.trace_dispatch)
         if not isinstance(cmd, types.CodeType):
             cmd = compile(cmd, "<string>", "exec")
         
+        if debug:
+            sys.settrace(self.trace_dispatch)
+        
         try:
             exec(cmd, globals, locals)
+            atexit._run_exitfuncs()
+            self._dbgClient.progTerminated(0)
         except SystemExit:
-            pass
+            atexit._run_exitfuncs()
+            excinfo = sys.exc_info()
+            exitcode, message = self.__extractSystemExitMessage(excinfo)
+            self._dbgClient.progTerminated(exitcode, message)
+        except Exception:
+            excinfo = sys.exc_info()
+            self.user_exception(excinfo, True)
         finally:
             self.quitting = True
             sys.settrace(None)
@@ -767,12 +765,10 @@
         self.isBroken = False
         self._dbgClient.unlockClient()
         
-    def user_exception(self, frame, excinfo, unhandled=False):
+    def user_exception(self, excinfo, unhandled=False):
         """
         Public method reimplemented to report an exception to the debug server.
         
-        @param frame the frame object
-        @type frame object
         @param excinfo details about the exception
         @type tuple(Exception, excval object, traceback frame object)
         @keyparam unhandled flag indicating an uncaught exception
@@ -780,44 +776,10 @@
         """
         exctype, excval, exctb = excinfo
         
-        if exctype in [GeneratorExit, StopIteration]:
+        if exctype in [GeneratorExit, StopIteration, SystemExit]:
             # ignore these
             return
         
-        if exctype == SystemExit:
-            atexit._run_exitfuncs()
-            if excval is None:
-                exitcode = 0
-                message = ""
-            elif isinstance(excval, basestring):
-                exitcode = 1
-                message = excval
-            elif isinstance(excval, bytes):
-                exitcode = 1
-                message = excval.decode()
-            elif isinstance(excval, int):
-                exitcode = excval
-                message = ""
-            elif isinstance(excval, SystemExit):
-                code = excval.code
-                if isinstance(code, basestring):
-                    exitcode = 1
-                    message = code
-                elif isinstance(code, bytes):
-                    exitcode = 1
-                    message = code.decode()
-                elif isinstance(code, int):
-                    exitcode = code
-                    message = ""
-                else:
-                    exitcode = 1
-                    message = str(code)
-            else:
-                exitcode = 1
-                message = str(excval)
-            self._dbgClient.progTerminated(exitcode, message)
-            return
-        
         if exctype in [SyntaxError, IndentationError]:
             try:
                 # tuple could only occure on Python 2, but not always!
@@ -934,6 +896,48 @@
         tb = None
         return stack
 
+    def __extractSystemExitMessage(self, excinfo):
+        """
+        Private method to get the SystemExit code and message.
+        
+        @param excinfo details about the SystemExit exception
+        @type tuple(Exception, excval object, traceback frame object)
+        @return SystemExit code and message
+        @rtype int, str
+        """
+        exctype, excval, exctb = excinfo
+        if excval is None:
+            exitcode = 0
+            message = ""
+        elif isinstance(excval, basestring):
+            exitcode = 1
+            message = excval
+        elif isinstance(excval, bytes):
+            exitcode = 1
+            message = excval.decode()
+        elif isinstance(excval, int):
+            exitcode = excval
+            message = ""
+        elif isinstance(excval, SystemExit):
+            code = excval.code
+            if isinstance(code, basestring):
+                exitcode = 1
+                message = code
+            elif isinstance(code, bytes):
+                exitcode = 1
+                message = code.decode()
+            elif isinstance(code, int):
+                exitcode = code
+                message = ""
+            else:
+                exitcode = 1
+                message = str(code)
+        else:
+            exitcode = 1
+            message = str(excval)
+        
+        return exitcode, message
+
     def stop_here(self, frame):
         """
         Public method reimplemented to filter out debugger files.
--- a/DebugClients/Python/DebugClientBase.py	Mon Feb 20 19:27:37 2017 +0100
+++ b/DebugClients/Python/DebugClientBase.py	Mon Feb 20 19:32:48 2017 +0100
@@ -494,8 +494,7 @@
             code = self.__compileFileSource(self.running)
             if code:
                 sys.setprofile(self.callTraceEnabled)
-                res = self.mainThread.run(code, self.debugMod.__dict__)
-                self.progTerminated(res)
+                self.mainThread.run(code, self.debugMod.__dict__, debug=True)
 
         elif method == "RequestRun":
             sys.argv = []
@@ -529,13 +528,7 @@
             res = 0
             code = self.__compileFileSource(self.running)
             if code:
-                try:
-                    exec(code, self.debugMod.__dict__)
-                except SystemExit as exc:
-                    res = exc.code
-                    atexit._run_exitfuncs()
-                self.writestream.flush()
-                self.progTerminated(res)
+                self.mainThread.run(code, self.debugMod.__dict__, debug=False)
 
         elif method == "RequestCoverage":
             from coverage import coverage
@@ -567,17 +560,10 @@
             code = self.__compileFileSource(sys.argv[0])
             if code:
                 self.running = sys.argv[0]
-                res = 0
                 self.cover.start()
-                try:
-                    exec(code, self.debugMod.__dict__)
-                except SystemExit as exc:
-                    res = exc.code
-                    atexit._run_exitfuncs()
+                self.mainThread.run(code, self.debugMod.__dict__, debug=False)
                 self.cover.stop()
                 self.cover.save()
-                self.writestream.flush()
-                self.progTerminated(res)
         
         elif method == "RequestProfile":
             sys.setprofile(None)
@@ -618,12 +604,15 @@
                 res = 0
                 try:
                     self.prof.run(script)
+                    atexit._run_exitfuncs()
                 except SystemExit as exc:
                     res = exc.code
-                    
-                atexit._run_exitfuncs()
+                    atexit._run_exitfuncs()
+                except Exception:
+                    excinfo = sys.exc_info()
+                    self.__unhandled_exception(*excinfo)
+                
                 self.prof.save()
-                self.writestream.flush()
                 self.progTerminated(res)
         
         elif method == "ExecuteStatement":
@@ -1189,7 +1178,7 @@
         @param excval data about the exception
         @param exctb traceback for the exception
         """
-        self.mainThread.user_exception(None, (exctype, excval, exctb), True)
+        self.mainThread.user_exception((exctype, excval, exctb), True)
     
     def __interceptSignals(self):
         """

eric ide

mercurial