DebugClients/Python/ThreadExtension.py

branch
debugger fine grinding
changeset 5552
313a91a38aed
parent 5544
5a90f78a73c9
child 5561
5fffb5cc1a88
--- a/DebugClients/Python/ThreadExtension.py	Thu Feb 23 21:40:26 2017 +0100
+++ b/DebugClients/Python/ThreadExtension.py	Thu Feb 23 22:13:28 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

eric ide

mercurial