--- a/DebugClients/Python3/DebugBase.py Thu Jun 23 19:24:09 2016 +0200 +++ b/DebugClients/Python3/DebugBase.py Sun Jun 26 16:32:01 2016 +0200 @@ -49,6 +49,13 @@ Provides simple wrapper methods around bdb for the 'owning' client to call to step etc. """ + # Don't thrust distutils.sysconfig.get_python_lib: possible case mismatch + # on Windows + lib = os.path.dirname(bdb.__file__) + # tuple required because it's accessed a lot of times by startswith method + pathsToSkip = ('<', os.path.dirname(__file__), bdb.__file__[:-1]) + filesToSkip = {} + def __init__(self, dbgClient): """ Constructor @@ -61,6 +68,7 @@ self._mainThread = True self.breaks = self._dbgClient.breakpoints + self.tracePythonLibs(0) self.__event = "" self.__isBroken = "" @@ -198,7 +206,8 @@ @param toFrame destination frame (frame) """ if self._dbgClient.callTraceEnabled: - if not self.__skip_it(fromFrame) and not self.__skip_it(toFrame): + if (not self.__skipFrame(fromFrame) and + not self.__skipFrame(toFrame)): if event in ["call", "return"]: fr = fromFrame fromStr = "{0}:{1}:{2}".format( @@ -297,7 +306,7 @@ @return local trace function @exception bdb.BdbQuit raised to indicate the end of the debug session """ - if not self.__skip_it(frame): + if not self.__skipFrame(frame): # When stepping with next/until/return in a generator frame, # skip the internal StopIteration exception (with no traceback) # triggered by a subiterator run with the 'yield from' @@ -845,12 +854,31 @@ @param frame the frame object @return flag indicating whether the debugger should stop here """ - if self.__skip_it(frame): + if self.__skipFrame(frame): return False return bdb.Bdb.stop_here(self, frame) - def __skip_it(self, frame): + def tracePythonLibs(self, enable): + """ + Public methode to update the settings to trace into Python libraries. + + @param enable let's debug into Python libraries (int) + """ + pathsToSkip = list(self.pathsToSkip) + # don't trace into Python library? + if enable: + pathsToSkip = [x for x in pathsToSkip if not x.endswith( + ("site-packages", "dist-packages", self.lib))] + else: + pathsToSkip.append(self.lib) + localLib = [x for x in sys.path if x.endswith(("site-packages", + "dist-packages")) and not x.startswith(self.lib)] + pathsToSkip.extend(localLib) + + self.pathsToSkip = tuple(pathsToSkip) + + def __skipFrame(self, frame): """ Private method to filter out debugger files. @@ -860,33 +888,15 @@ @param frame the frame object @return flag indicating whether the debugger should skip this frame """ - if frame is None: - return True - - fn = self.fix_frame_filename(frame) - - # Eliminate things like <string> and <stdin>. - if fn[0] == '<': + try: + return self.filesToSkip[frame.f_code.co_filename] + except KeyError: + ret = frame.f_code.co_filename.startswith(self.pathsToSkip) + self.filesToSkip[frame.f_code.co_filename] = ret + return ret + except AttributeError: + # if frame is None return True - - #XXX - think of a better way to do this. It's only a convenience for - #debugging the debugger - when the debugger code is in the current - #directory. - if os.path.basename(fn) in [ - 'AsyncFile.py', 'AsyncIO.py', - 'DebugConfig.py', 'DCTestResult.py', - 'DebugBase.py', 'DebugClientBase.py', - 'DebugClientCapabilities.py', 'DebugClient.py', - 'DebugClientThreads.py', 'DebugProtocol.py', - 'DebugThread.py', 'FlexCompleter.py', - 'PyProfile.py'] or \ - os.path.dirname(fn).endswith("coverage"): - return True - - if self._dbgClient.shouldSkip(fn): - return True - - return False def isBroken(self): """