--- a/DebugClients/Python3/DebugBase.py Sun Jun 26 21:29:18 2016 +0200 +++ b/DebugClients/Python3/DebugBase.py Fri Jul 01 21:54:07 2016 +0200 @@ -56,6 +56,9 @@ pathsToSkip = ('<', os.path.dirname(__file__), bdb.__file__[:-1]) filesToSkip = {} + # cache for fixed file names + _fnCache = {} + def __init__(self, dbgClient): """ Constructor @@ -378,23 +381,28 @@ code over a network... This logic deals with that. @param frame the frame object - @return fixed up file name (string) + @type frame object + @return fixed up file name + @rtype str """ # get module name from __file__ - if '__file__' in frame.f_globals and \ - frame.f_globals['__file__'] and \ - frame.f_globals['__file__'] == frame.f_code.co_filename: - root, ext = os.path.splitext(frame.f_globals['__file__']) - if ext in ['.pyc', '.py', '.py3', '.pyo']: - fixedName = root + '.py' - if os.path.exists(fixedName): - return fixedName - - fixedName = root + '.py3' - if os.path.exists(fixedName): - return fixedName - - return frame.f_code.co_filename + fn = frame.f_globals.get('__file__') + try: + return self._fnCache[fn] + except KeyError: + if fn and fn != frame.f_code.co_filename: + absFilename = os.path.abspath(fn) + if absFilename.endswith(('.pyc', '.pyo')): + fixedName = absFilename[:-1] + if not os.path.exists(fixedName): + fixedName = absFilename + else: + fixedName = absFilename + else: + fixedName = frame.f_code.co_filename + # update cache + self._fnCache[fn] = fixedName + return fixedName def set_watch(self, cond, temporary=False): """ @@ -521,7 +529,7 @@ @param frame the frame object @return flag indicating the break status (boolean) """ - filename = self.canonic(self.fix_frame_filename(frame)) + filename = self.fix_frame_filename(frame) if filename not in self.breaks and "Watch" not in self.breaks: return False @@ -563,9 +571,32 @@ @return flag indicating the break status (boolean) """ return \ - self.canonic(self.fix_frame_filename(frame)) in self.breaks or \ + self.fix_frame_filename(frame) in self.breaks or \ ("Watch" in self.breaks and self.breaks["Watch"]) + def set_break(self, filename, lineno, temporary=0, cond=None, + funcname=None): + """ + Public method reimplemented from bdb.py to normalize the filename and + set as a breakpoint. + + @param filename the filename where a breakpoint is set + @type str + @param lineno the line number of the breakpoint + @type int + @keyparam temporary flag to indicate a temporary breakpoint + @type int + @keyparam cond Python expression which dynamically enables this bp + @type str + @keyparam funcname name of the function (unused) + @type str or None + """ + filename = os.path.abspath(filename) + list = self.breaks.setdefault(filename, []) + if lineno not in list: + list.append(lineno) + bdb.Breakpoint(filename, lineno, temporary, cond, funcname) + def get_break(self, filename, lineno): """ Public method reimplemented from bdb.py to get the first breakpoint of @@ -574,15 +605,33 @@ Because eric6 supports only one breakpoint per line, this overwritten method will return this one and only breakpoint. - @param filename the filename of the bp to retrieve (string) - @param lineno the linenumber of the bp to retrieve (integer) + @param filename the filename of the bp to retrieve + @type str + @param lineno the linenumber of the bp to retrieve + @type int @return breakpoint or None, if there is no bp + @rtype breakpoint object or None + """ + return (lineno in self.breaks.get(filename, []) and + bdb.Breakpoint.bplist[filename, lineno][0] or None) + + def clear_break(self, filename, lineno): """ - filename = self.canonic(filename) - return filename in self.breaks and \ - lineno in self.breaks[filename] and \ - bdb.Breakpoint.bplist[filename, lineno][0] or None - + Public method reimplemented from bdb.py to clear a breakpoint. + + @param filename the filename of the bp to retrieve + @type str + @param lineno the linenumber of the bp to retrieve + @type int + """ + if (filename, lineno) not in bdb.Breakpoint.bplist: + return + # If there's only one bp in the list for that file,line + # pair, then remove the breaks entry + for bp in bdb.Breakpoint.bplist[filename, lineno][:]: + bp.deleteMe() + self._prune_breaks(filename, lineno) + def __do_clear(self, filename, lineno): """ Private method called to clear a temporary breakpoint. @@ -861,9 +910,10 @@ def tracePythonLibs(self, enable): """ - Public methode to update the settings to trace into Python libraries. + Public method to update the settings to trace into Python libraries. - @param enable let's debug into Python libraries (int) + @param enable flag to debug into Python libraries + @type int """ pathsToSkip = list(self.pathsToSkip) # don't trace into Python library? @@ -886,7 +936,9 @@ debugger that are called from the application being debugged. @param frame the frame object + @type frame object @return flag indicating whether the debugger should skip this frame + @rtype bool """ try: return self.filesToSkip[frame.f_code.co_filename]