diff -r 884cd9c9ce05 -r b93cb6353cc0 DebugClients/Python/ThreadExtension.py --- a/DebugClients/Python/ThreadExtension.py Thu Mar 23 18:58:56 2017 +0100 +++ b/DebugClients/Python/ThreadExtension.py Fri Apr 07 18:33:59 2017 +0200 @@ -39,6 +39,7 @@ self._original_start_new_thread = None self.threadingAttached = False self.qtThreadAttached = False + self.greenlet = False self.clientLock = threading.RLock() @@ -64,7 +65,7 @@ sys.meta_path.insert(0, self) - def attachThread(self, target=None, args=None, kwargs={}, + def attachThread(self, target=None, args=None, kwargs=None, mainThread=False): """ Public method to setup a standard thread for DebugClient to debug. @@ -80,6 +81,9 @@ started mainthread of the app @return identifier of the created thread """ + if kwargs is None: + kwargs = {} + if mainThread: ident = _thread.get_ident() name = 'MainThread' @@ -140,19 +144,19 @@ except AssertionError: pass - def setCurrentThread(self, id): + def setCurrentThread(self, threadId): """ Public method to set the current thread. - @param id the id the current thread should be set to. + @param threadId the id the current thread should be set to. @type int """ try: self.lockClient() - if id is None: + if threadId is None: self.currentThread = None else: - self.currentThread = self.threads.get(id) + self.currentThread = self.threads.get(threadId) finally: self.unlockClient() @@ -167,10 +171,10 @@ # update thread names set by user (threading.setName) threadNames = {t.ident: t.getName() for t in threading.enumerate()} - for id, thd in self.threads.items(): - d = {"id": id} + for threadId, thd in self.threads.items(): + d = {"id": threadId} try: - d["name"] = threadNames.get(id, thd.name) + d["name"] = threadNames.get(threadId, thd.name) d["broken"] = thd.isBroken except Exception: d["name"] = 'UnknownThread' @@ -215,28 +219,28 @@ Public method to update the list of running threads. """ frames = sys._current_frames() - for id, frame in frames.items(): + for threadId, frame in frames.items(): # skip our own timer thread if frame.f_code.co_name == '__eventPollTimer': continue # Unknown thread - if id not in self.threads: + if threadId not in self.threads: newThread = DebugBase(self) name = 'Thread-{0}'.format(self.threadNumber) self.threadNumber += 1 - newThread.id = id + newThread.id = threadId newThread.name = name - self.threads[id] = newThread + self.threads[threadId] = newThread # adjust current frame if "__pypy__" not in sys.builtin_module_names: # Don't update with None currentFrame = self.getExecutedFrame(frame) if (currentFrame is not None and - self.threads[id].isBroken is False): - self.threads[id].currentFrame = currentFrame + self.threads[threadId].isBroken is False): + self.threads[threadId].currentFrame = currentFrame # Clean up obsolet because terminated threads self.threads = {id_: thrd for id_, thrd in self.threads.items() @@ -257,7 +261,7 @@ return None if fullname in [self.threadModName, 'PyQt4.QtCore', 'PyQt5.QtCore', - 'PySide.QtCore', 'PySide2.QtCore', + 'PySide.QtCore', 'PySide2.QtCore', 'greenlet', 'threading'] and self.enableImportHooks: # Disable hook to be able to import original module self.enableImportHooks = False @@ -282,6 +286,14 @@ self._original_start_new_thread = module.start_new_thread module.start_new_thread = self.attachThread + elif (fullname == 'greenlet' and self.greenlet is False): + # Check for greenlet.settrace + if hasattr(module, 'settrace'): + self.greenlet = True + DebugBase.pollTimerEnabled = False + + # TODO: Implement the debugger extension for greenlets + # Add hook for threading.run() elif (fullname == "threading" and self.threadingAttached is False): self.threadingAttached = True @@ -297,7 +309,8 @@ @param run the run method of threading.Thread @type method pointer """ - newThread = _debugClient.threads[self.ident] + newThread = DebugBase(_debugClient) + _debugClient.threads[self.ident] = newThread newThread.name = self.name # see DebugBase.bootstrap sys.settrace(newThread.trace_dispatch)