Merged with debugger changes done by Tobias.

Fri, 24 Feb 2017 18:51:36 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Fri, 24 Feb 2017 18:51:36 +0100
changeset 5553
d0e3207d1e8f
parent 5549
fa21bfab0a29 (current diff)
parent 5552
313a91a38aed (diff)
child 5554
c477ae02bf5f

Merged with debugger changes done by Tobias.

changelog file | annotate | diff | comparison | revisions
diff -r fa21bfab0a29 -r d0e3207d1e8f DebugClients/Python/DebugBase.py
--- a/DebugClients/Python/DebugBase.py	Thu Feb 23 19:15:36 2017 +0100
+++ b/DebugClients/Python/DebugBase.py	Fri Feb 24 18:51:36 2017 +0100
@@ -317,7 +317,7 @@
                 return self.trace_dispatch
             else:
                 # No need to trace this function
-                return 
+                return
         
         if event == 'return':
             return
@@ -420,8 +420,10 @@
         @type str or CodeType
         @keyparam globals dictionary of global variables for cmd
         @type dict
-        @keyparam locals  dictionary of local variables for cmd
+        @keyparam locals dictionary of local variables for cmd
         @type dict
+        @keyparam debug flag if command should run under debugger control
+        @type bool
         """
         if globals is None:
             import __main__
diff -r fa21bfab0a29 -r d0e3207d1e8f DebugClients/Python/DebugClientBase.py
--- a/DebugClients/Python/DebugClientBase.py	Thu Feb 23 19:15:36 2017 +0100
+++ b/DebugClients/Python/DebugClientBase.py	Fri Feb 24 18:51:36 2017 +0100
@@ -727,7 +727,7 @@
                 self.eventExit = True
         
         elif method == "RequestContinue":
-            self.currentThread.go(params["special"])
+            self.currentThreadExec.go(params["special"])
             self.eventExit = True
         
         elif method == "RawInput":
diff -r fa21bfab0a29 -r d0e3207d1e8f DebugClients/Python/ThreadExtension.py
--- a/DebugClients/Python/ThreadExtension.py	Thu Feb 23 19:15:36 2017 +0100
+++ b/DebugClients/Python/ThreadExtension.py	Fri Feb 24 18:51:36 2017 +0100
@@ -20,6 +20,8 @@
 
 from DebugBase import DebugBase
 
+_qtThreadNumber = 1
+
 
 class ThreadExtension(object):
     """
@@ -36,7 +38,7 @@
         self.enableImportHooks = True
         self._original_start_new_thread = None
         self.threadingAttached = False
-        self._qtThread = None
+        self.qtThreadAttached = False
         
         self.clientLock = threading.RLock()
         
@@ -285,6 +287,12 @@
             _debugClient = self
             
             def _bootstrap(self, run):
+                """
+                Bootstrap for threading, which reports exceptions correctly.
+                
+                @param run the run method of threading.Thread
+                @type method pointer
+                """
                 newThread = _debugClient.threads[self.ident]
                 newThread.name = self.name
                 # see DebugBase.bootstrap
@@ -296,6 +304,7 @@
                     newThread.user_exception(excinfo, True)
             
             class ThreadWrapper(module.Thread):
+                """ Wrapper class for threading.Thread. """
                 
                 def __init__(self, *args, **kwargs):
                     # Overwrite the provided run method with our own, to
@@ -306,50 +315,61 @@
             
             module.Thread = ThreadWrapper
         
+        # Add hook for *.QThread
         elif (fullname in ['PyQt4.QtCore', 'PyQt5.QtCore',
                            'PySide.QtCore', 'PySide2.QtCore'] and
-                self._qtThread is None):
-            self._qtThread = module.QThread
+                self.qtThreadAttached is False):
+            self.qtThreadAttached = True
             # _debugClient as a class attribute can't be accessed in following
             # class. Therefore we need a global variable.
             _debugClient = self
+
+            def _bootstrapQThread(self, run):
+                """
+                Bootstrap for QThread, which reports exceptions correctly.
+                
+                @param run the run method of *.QThread
+                @type method pointer
+                """
+                global _qtThreadNumber
+                
+                newThread = DebugBase(_debugClient)
+                ident = _thread.get_ident()
+                name = 'QtThread-{0}'.format(_qtThreadNumber)
+                
+                _qtThreadNumber += 1
             
+                newThread.id = ident
+                newThread.name = name
+                
+                _debugClient.threads[ident] = newThread
+                
+                # see DebugBase.bootstrap
+                sys.settrace(newThread.trace_dispatch)
+                try:
+                    run()
+                except SystemExit:
+                    # *.QThreads doesn't like SystemExit
+                    pass
+                except Exception:
+                    excinfo = sys.exc_info()
+                    newThread.user_exception(excinfo, True)
+        
             class QThreadWrapper(module.QThread):
-                __qtThreadNumber = 1
+                """ Wrapper class for *.QThread. """
                 
                 def __init__(self, *args, **kwargs):
                     # Overwrite the provided run method with our own, to
                     # intercept the thread creation by Qt
-                    self._ApplicationRun = self.run
-                    self.run = self.__bootstrapQThread
+                    self.run = lambda s=self, run=self.run: (
+                        _bootstrapQThread(s, run))
                     
                     super(QThreadWrapper, self).__init__(*args, **kwargs)
-                
-                def __bootstrapQThread(self):
-                    newThread = DebugBase(_debugClient)
-                    ident = _thread.get_ident()
-                    name = 'QtThread-{0}'.format(self.__qtThreadNumber)
-                    self.__qtThreadNumber += 1
-                
-                    newThread.id = ident
-                    newThread.name = name
-                    
-                    _debugClient.threads[ident] = newThread
-                    
-                    frame = sys._getframe()
-                    newThread.botframe = frame
-                    frame.f_trace = newThread.trace_dispatch
-                    # see DebugBase.bootstrap
-                    sys.settrace(
-                        lambda frame, event, arg: newThread.trace_dispatch)
-                    
-                    return self._ApplicationRun()
             
             module.QThread = QThreadWrapper
         
         self.enableImportHooks = True
         return module
 
-
 #
 # eflag: noqa = M702
diff -r fa21bfab0a29 -r d0e3207d1e8f changelog
--- a/changelog	Thu Feb 23 19:15:36 2017 +0100
+++ b/changelog	Fri Feb 24 18:51:36 2017 +0100
@@ -5,6 +5,10 @@
 - Checkers
   -- upgraded pycodestyle to version 2.3.1
   -- upgraded pyflakes to version 1.5.0
+- Debugger
+  -- catch unhandled exceptions again
+  -- support for PySide2 added
+  -- atexit handling works as specified in any condition
 - Mercurial Interface
   -- improved the log browser in several ways
   -- improved the status dialog

eric ide

mercurial