同步操作将从 OpenHarmony-SIG/python 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
"""Debugger basics"""import fnmatchimport sysimport osfrom inspect import CO_GENERATOR, CO_COROUTINE, CO_ASYNC_GENERATOR__all__ = ["BdbQuit", "Bdb", "Breakpoint"]GENERATOR_AND_COROUTINE_FLAGS = CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATORclass BdbQuit(Exception):"""Exception to give up completely."""class Bdb:"""Generic Python debugger base class.This class takes care of details of the trace facility;a derived class should implement user interaction.The standard debugger class (pdb.Pdb) is an example.The optional skip argument must be an iterable of glob-stylemodule name patterns. The debugger will not step into framesthat originate in a module that matches one of these patterns.Whether a frame is considered to originate in a certain moduleis determined by the __name__ in the frame globals."""def __init__(self, skip=None):self.skip = set(skip) if skip else Noneself.breaks = {}self.fncache = {}self.frame_returning = Nonedef canonic(self, filename):"""Return canonical form of filename.For real filenames, the canonical form is a case-normalized (oncase insensitive filesystems) absolute path. 'Filenames' withangle brackets, such as "<stdin>", generated in interactivemode, are returned unchanged."""if filename == "<" + filename[1:-1] + ">":return filenamecanonic = self.fncache.get(filename)if not canonic:canonic = os.path.abspath(filename)canonic = os.path.normcase(canonic)self.fncache[filename] = canonicreturn canonicdef reset(self):"""Set values of attributes as ready to start debugging."""import linecachelinecache.checkcache()self.botframe = Noneself._set_stopinfo(None, None)def trace_dispatch(self, frame, event, arg):"""Dispatch a trace function for debugged frames based on the event.This function is installed as the trace function for debuggedframes. Its return value is the new trace function, which isusually itself. The default implementation decides how todispatch a frame, depending on the type of event (passed in as astring) that is about to be executed.The event can be one of the following:line: A new line of code is going to be executed.call: A function is about to be called or another code blockis entered.return: A function or other code block is about to return.exception: An exception has occurred.c_call: A C function is about to be called.c_return: A C function has returned.c_exception: A C function has raised an exception.For the Python events, specialized functions (see the dispatch_*()methods) are called. For the C events, no action is taken.The arg parameter depends on the previous event."""if self.quitting:return # Noneif event == 'line':return self.dispatch_line(frame)if event == 'call':return self.dispatch_call(frame, arg)if event == 'return':return self.dispatch_return(frame, arg)if event == 'exception':return self.dispatch_exception(frame, arg)if event == 'c_call':return self.trace_dispatchif event == 'c_exception':return self.trace_dispatchif event == 'c_return':return self.trace_dispatchprint('bdb.Bdb.dispatch: unknown debugging event:', repr(event))return self.trace_dispatchdef dispatch_line(self, frame):"""Invoke user function and return trace function for line event.If the debugger stops on the current line, invokeself.user_line(). Raise BdbQuit if self.quitting is set.Return self.trace_dispatch to continue tracing in this scope."""if self.stop_here(frame) or self.break_here(frame):self.user_line(frame)if self.quitting: raise BdbQuitreturn self.trace_dispatchdef dispatch_call(self, frame, arg):"""Invoke user function and return trace function for call event.If the debugger stops on this function call, invokeself.user_call(). Raise BbdQuit if self.quitting is set.Return self.trace_dispatch to continue tracing in this scope."""# XXX 'arg' is no longer usedif self.botframe is None:# First call of dispatch since reset()self.botframe = frame.f_back # (CT) Note that this may also be None!return self.trace_dispatchif not (self.stop_here(frame) or self.break_anywhere(frame)):# No need to trace this functionreturn # None# Ignore call events in generator except when stepping.if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:return self.trace_dispatchself.user_call(frame, arg)if self.quitting: raise BdbQuitreturn self.trace_dispatchdef dispatch_return(self, frame, arg):"""Invoke user function and return trace function for return event.If the debugger stops on this function return, invokeself.user_return(). Raise BdbQuit if self.quitting is set.Return self.trace_dispatch to continue tracing in this scope."""if self.stop_here(frame) or frame == self.returnframe:# Ignore return events in generator except when stepping.if self.stopframe and frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:return self.trace_dispatchtry:self.frame_returning = frameself.user_return(frame, arg)finally:self.frame_returning = Noneif self.quitting: raise BdbQuit# The user issued a 'next' or 'until' command.if self.stopframe is frame and self.stoplineno != -1:self._set_stopinfo(None, None)return self.trace_dispatchdef dispatch_exception(self, frame, arg):"""Invoke user function and return trace function for exception event.If the debugger stops on this exception, invokeself.user_exception(). Raise BdbQuit if self.quitting is set.Return self.trace_dispatch to continue tracing in this scope."""if self.stop_here(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' statement.if not (frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGSand arg[0] is StopIteration and arg[2] is None):self.user_exception(frame, arg)if self.quitting: raise BdbQuit# Stop at the StopIteration or GeneratorExit exception when the user# has set stopframe in a generator by issuing a return command, or a# next/until command at the last statement in the generator before the# exception.elif (self.stopframe and frame is not self.stopframeand self.stopframe.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGSand arg[0] in (StopIteration, GeneratorExit)):self.user_exception(frame, arg)if self.quitting: raise BdbQuitreturn self.trace_dispatch# Normally derived classes don't override the following# methods, but they may if they want to redefine the# definition of stopping and breakpoints.def is_skipped_module(self, module_name):"Return True if module_name matches any skip pattern."if module_name is None: # some modules do not have namesreturn Falsefor pattern in self.skip:if fnmatch.fnmatch(module_name, pattern):return Truereturn Falsedef stop_here(self, frame):"Return True if frame is below the starting frame in the stack."# (CT) stopframe may now also be None, see dispatch_call.# (CT) the former test for None is therefore removed from here.if self.skip and \self.is_skipped_module(frame.f_globals.get('__name__')):return Falseif frame is self.stopframe:if self.stoplineno == -1:return Falsereturn frame.f_lineno >= self.stoplinenoif not self.stopframe:return Truereturn Falsedef break_here(self, frame):"""Return True if there is an effective breakpoint for this line.Check for line or function breakpoint and if in effect.Delete temporary breakpoints if effective() says to."""filename = self.canonic(frame.f_code.co_filename)if filename not in self.breaks:return Falselineno = frame.f_linenoif lineno not in self.breaks[filename]:# The line itself has no breakpoint, but maybe the line is the# first line of a function with breakpoint set by function name.lineno = frame.f_code.co_firstlinenoif lineno not in self.breaks[filename]:return False# flag says ok to delete temp. bp(bp, flag) = effective(filename, lineno, frame)if bp:self.currentbp = bp.numberif (flag and bp.temporary):self.do_clear(str(bp.number))return Trueelse:return Falsedef do_clear(self, arg):"""Remove temporary breakpoint.Must implement in derived classes or get NotImplementedError."""raise NotImplementedError("subclass of bdb must implement do_clear()")def break_anywhere(self, frame):"""Return True if there is any breakpoint for frame's filename."""return self.canonic(frame.f_code.co_filename) in self.breaks# Derived classes should override the user_* methods# to gain control.def user_call(self, frame, argument_list):"""Called if we might stop in a function."""passdef user_line(self, frame):"""Called when we stop or break at a line."""passdef user_return(self, frame, return_value):"""Called when a return trap is set here."""passdef user_exception(self, frame, exc_info):"""Called when we stop on an exception."""passdef _set_stopinfo(self, stopframe, returnframe, stoplineno=0):"""Set the attributes for stopping.If stoplineno is greater than or equal to 0, then stop at linegreater than or equal to the stopline. If stoplineno is -1, thendon't stop at all."""self.stopframe = stopframeself.returnframe = returnframeself.quitting = False# stoplineno >= 0 means: stop at line >= the stoplineno# stoplineno -1 means: don't stop at allself.stoplineno = stoplineno# Derived classes and clients can call the following methods# to affect the stepping state.def set_until(self, frame, lineno=None):"""Stop when the line with the lineno greater than the current one isreached or when returning from current frame."""# the name "until" is borrowed from gdbif lineno is None:lineno = frame.f_lineno + 1self._set_stopinfo(frame, frame, lineno)def set_step(self):"""Stop after one line of code."""# Issue #13183: pdb skips frames after hitting a breakpoint and running# step commands.# Restore the trace function in the caller (that may not have been set# for performance reasons) when returning from the current frame.if self.frame_returning:caller_frame = self.frame_returning.f_backif caller_frame and not caller_frame.f_trace:caller_frame.f_trace = self.trace_dispatchself._set_stopinfo(None, None)def set_next(self, frame):"""Stop on the next line in or below the given frame."""self._set_stopinfo(frame, None)def set_return(self, frame):"""Stop when returning from the given frame."""if frame.f_code.co_flags & GENERATOR_AND_COROUTINE_FLAGS:self._set_stopinfo(frame, None, -1)else:self._set_stopinfo(frame.f_back, frame)def set_trace(self, frame=None):"""Start debugging from frame.If frame is not specified, debugging starts from caller's frame."""if frame is None:frame = sys._getframe().f_backself.reset()while frame:frame.f_trace = self.trace_dispatchself.botframe = frameframe = frame.f_backself.set_step()sys.settrace(self.trace_dispatch)def set_continue(self):"""Stop only at breakpoints or when finished.If there are no breakpoints, set the system trace function to None."""# Don't stop except at breakpoints or when finishedself._set_stopinfo(self.botframe, None, -1)if not self.breaks:# no breakpoints; run without debugger overheadsys.settrace(None)frame = sys._getframe().f_backwhile frame and frame is not self.botframe:del frame.f_traceframe = frame.f_backdef set_quit(self):"""Set quitting attribute to True.Raises BdbQuit exception in the next call to a dispatch_*() method."""self.stopframe = self.botframeself.returnframe = Noneself.quitting = Truesys.settrace(None)# Derived classes and clients can call the following methods# to manipulate breakpoints. These methods return an# error message if something went wrong, None if all is well.# Set_break prints out the breakpoint line and file:lineno.# Call self.get_*break*() to see the breakpoints or better# for bp in Breakpoint.bpbynumber: if bp: bp.bpprint().def set_break(self, filename, lineno, temporary=False, cond=None,funcname=None):"""Set a new breakpoint for filename:lineno.If lineno doesn't exist for the filename, return an error message.The filename should be in canonical form."""filename = self.canonic(filename)import linecache # Import as late as possibleline = linecache.getline(filename, lineno)if not line:return 'Line %s:%d does not exist' % (filename, lineno)list = self.breaks.setdefault(filename, [])if lineno not in list:list.append(lineno)bp = Breakpoint(filename, lineno, temporary, cond, funcname)return Nonedef _prune_breaks(self, filename, lineno):"""Prune breakpoints for filename:lineno.A list of breakpoints is maintained in the Bdb instance and inthe Breakpoint class. If a breakpoint in the Bdb instance nolonger exists in the Breakpoint class, then it's removed from theBdb instance."""if (filename, lineno) not in Breakpoint.bplist:self.breaks[filename].remove(lineno)if not self.breaks[filename]:del self.breaks[filename]def clear_break(self, filename, lineno):"""Delete breakpoints for filename:lineno.If no breakpoints were set, return an error message."""filename = self.canonic(filename)if filename not in self.breaks:return 'There are no breakpoints in %s' % filenameif lineno not in self.breaks[filename]:return 'There is no breakpoint at %s:%d' % (filename, lineno)# If there's only one bp in the list for that file,line# pair, then remove the breaks entryfor bp in Breakpoint.bplist[filename, lineno][:]:bp.deleteMe()self._prune_breaks(filename, lineno)return Nonedef clear_bpbynumber(self, arg):"""Delete a breakpoint by its index in Breakpoint.bpbynumber.If arg is invalid, return an error message."""try:bp = self.get_bpbynumber(arg)except ValueError as err:return str(err)bp.deleteMe()self._prune_breaks(bp.file, bp.line)return Nonedef clear_all_file_breaks(self, filename):"""Delete all breakpoints in filename.If none were set, return an error message."""filename = self.canonic(filename)if filename not in self.breaks:return 'There are no breakpoints in %s' % filenamefor line in self.breaks[filename]:blist = Breakpoint.bplist[filename, line]for bp in blist:bp.deleteMe()del self.breaks[filename]return Nonedef clear_all_breaks(self):"""Delete all existing breakpoints.If none were set, return an error message."""if not self.breaks:return 'There are no breakpoints'for bp in Breakpoint.bpbynumber:if bp:bp.deleteMe()self.breaks = {}return Nonedef get_bpbynumber(self, arg):"""Return a breakpoint by its index in Breakpoint.bybpnumber.For invalid arg values or if the breakpoint doesn't exist,raise a ValueError."""if not arg:raise ValueError('Breakpoint number expected')try:number = int(arg)except ValueError:raise ValueError('Non-numeric breakpoint number %s' % arg) from Nonetry:bp = Breakpoint.bpbynumber[number]except IndexError:raise ValueError('Breakpoint number %d out of range' % number) from Noneif bp is None:raise ValueError('Breakpoint %d already deleted' % number)return bpdef get_break(self, filename, lineno):"""Return True if there is a breakpoint for filename:lineno."""filename = self.canonic(filename)return filename in self.breaks and \lineno in self.breaks[filename]def get_breaks(self, filename, lineno):"""Return all breakpoints for filename:lineno.If no breakpoints are set, return an empty list."""filename = self.canonic(filename)return filename in self.breaks and \lineno in self.breaks[filename] and \Breakpoint.bplist[filename, lineno] or []def get_file_breaks(self, filename):"""Return all lines with breakpoints for filename.If no breakpoints are set, return an empty list."""filename = self.canonic(filename)if filename in self.breaks:return self.breaks[filename]else:return []def get_all_breaks(self):"""Return all breakpoints that are set."""return self.breaks# Derived classes and clients can call the following method# to get a data structure representing a stack trace.def get_stack(self, f, t):"""Return a list of (frame, lineno) in a stack trace and a size.List starts with original calling frame, if there is one.Size may be number of frames above or below f."""stack = []if t and t.tb_frame is f:t = t.tb_nextwhile f is not None:stack.append((f, f.f_lineno))if f is self.botframe:breakf = f.f_backstack.reverse()i = max(0, len(stack) - 1)while t is not None:stack.append((t.tb_frame, t.tb_lineno))t = t.tb_nextif f is None:i = max(0, len(stack) - 1)return stack, idef format_stack_entry(self, frame_lineno, lprefix=': '):"""Return a string with information about a stack entry.The stack entry frame_lineno is a (frame, lineno) tuple. Thereturn string contains the canonical filename, the function nameor '<lambda>', the input arguments, the return value, and theline of code (if it exists)."""import linecache, reprlibframe, lineno = frame_linenofilename = self.canonic(frame.f_code.co_filename)s = '%s(%r)' % (filename, lineno)if frame.f_code.co_name:s += frame.f_code.co_nameelse:s += "<lambda>"s += '()'if '__return__' in frame.f_locals:rv = frame.f_locals['__return__']s += '->'s += reprlib.repr(rv)line = linecache.getline(filename, lineno, frame.f_globals)if line:s += lprefix + line.strip()return s# The following methods can be called by clients to use# a debugger to debug a statement or an expression.# Both can be given as a string, or a code object.def run(self, cmd, globals=None, locals=None):"""Debug a statement executed via the exec() function.globals defaults to __main__.dict; locals defaults to globals."""if globals is None:import __main__globals = __main__.__dict__if locals is None:locals = globalsself.reset()if isinstance(cmd, str):cmd = compile(cmd, "<string>", "exec")sys.settrace(self.trace_dispatch)try:exec(cmd, globals, locals)except BdbQuit:passfinally:self.quitting = Truesys.settrace(None)def runeval(self, expr, globals=None, locals=None):"""Debug an expression executed via the eval() function.globals defaults to __main__.dict; locals defaults to globals."""if globals is None:import __main__globals = __main__.__dict__if locals is None:locals = globalsself.reset()sys.settrace(self.trace_dispatch)try:return eval(expr, globals, locals)except BdbQuit:passfinally:self.quitting = Truesys.settrace(None)def runctx(self, cmd, globals, locals):"""For backwards-compatibility. Defers to run()."""# B/W compatibilityself.run(cmd, globals, locals)# This method is more useful to debug a single function call.def runcall(*args, **kwds):"""Debug a single function call.Return the result of the function call."""if len(args) >= 2:self, func, *args = argselif not args:raise TypeError("descriptor 'runcall' of 'Bdb' object ""needs an argument")elif 'func' in kwds:func = kwds.pop('func')self, *args = argsimport warningswarnings.warn("Passing 'func' as keyword argument is deprecated",DeprecationWarning, stacklevel=2)else:raise TypeError('runcall expected at least 1 positional argument, ''got %d' % (len(args)-1))self.reset()sys.settrace(self.trace_dispatch)res = Nonetry:res = func(*args, **kwds)except BdbQuit:passfinally:self.quitting = Truesys.settrace(None)return resruncall.__text_signature__ = '($self, func, /, *args, **kwds)'def set_trace():"""Start debugging with a Bdb instance from the caller's frame."""Bdb().set_trace()class Breakpoint:"""Breakpoint class.Implements temporary breakpoints, ignore counts, disabling and(re)-enabling, and conditionals.Breakpoints are indexed by number through bpbynumber and bythe (file, line) tuple using bplist. The former points to asingle instance of class Breakpoint. The latter points to alist of such instances since there may be more than onebreakpoint per line.When creating a breakpoint, its associated filename should bein canonical form. If funcname is defined, a breakpoint hit will becounted when the first line of that function is executed. Aconditional breakpoint always counts a hit."""# XXX Keeping state in the class is a mistake -- this means# you cannot have more than one active Bdb instance.next = 1 # Next bp to be assignedbplist = {} # indexed by (file, lineno) tuplebpbynumber = [None] # Each entry is None or an instance of Bpt# index 0 is unused, except for marking an# effective break .... see effective()def __init__(self, file, line, temporary=False, cond=None, funcname=None):self.funcname = funcname# Needed if funcname is not None.self.func_first_executable_line = Noneself.file = file # This better be in canonical form!self.line = lineself.temporary = temporaryself.cond = condself.enabled = Trueself.ignore = 0self.hits = 0self.number = Breakpoint.nextBreakpoint.next += 1# Build the two listsself.bpbynumber.append(self)if (file, line) in self.bplist:self.bplist[file, line].append(self)else:self.bplist[file, line] = [self]def deleteMe(self):"""Delete the breakpoint from the list associated to a file:line.If it is the last breakpoint in that position, it also deletesthe entry for the file:line."""index = (self.file, self.line)self.bpbynumber[self.number] = None # No longer in listself.bplist[index].remove(self)if not self.bplist[index]:# No more bp for this f:l combodel self.bplist[index]def enable(self):"""Mark the breakpoint as enabled."""self.enabled = Truedef disable(self):"""Mark the breakpoint as disabled."""self.enabled = Falsedef bpprint(self, out=None):"""Print the output of bpformat().The optional out argument directs where the output is sentand defaults to standard output."""if out is None:out = sys.stdoutprint(self.bpformat(), file=out)def bpformat(self):"""Return a string with information about the breakpoint.The information includes the breakpoint number, temporarystatus, file:line position, break condition, number of times toignore, and number of times hit."""if self.temporary:disp = 'del 'else:disp = 'keep 'if self.enabled:disp = disp + 'yes 'else:disp = disp + 'no 'ret = '%-4dbreakpoint %s at %s:%d' % (self.number, disp,self.file, self.line)if self.cond:ret += '\n\tstop only if %s' % (self.cond,)if self.ignore:ret += '\n\tignore next %d hits' % (self.ignore,)if self.hits:if self.hits > 1:ss = 's'else:ss = ''ret += '\n\tbreakpoint already hit %d time%s' % (self.hits, ss)return retdef __str__(self):"Return a condensed description of the breakpoint."return 'breakpoint %s at %s:%s' % (self.number, self.file, self.line)# -----------end of Breakpoint class----------def checkfuncname(b, frame):"""Return True if break should happen here.Whether a break should happen depends on the way that b (the breakpoint)was set. If it was set via line number, check if b.line is the same asthe one in the frame. If it was set via function name, check if this isthe right function and if it is on the first executable line."""if not b.funcname:# Breakpoint was set via line number.if b.line != frame.f_lineno:# Breakpoint was set at a line with a def statement and the function# defined is called: don't break.return Falsereturn True# Breakpoint set via function name.if frame.f_code.co_name != b.funcname:# It's not a function call, but rather execution of def statement.return False# We are in the right frame.if not b.func_first_executable_line:# The function is entered for the 1st time.b.func_first_executable_line = frame.f_linenoif b.func_first_executable_line != frame.f_lineno:# But we are not at the first line number: don't break.return Falsereturn True# Determines if there is an effective (active) breakpoint at this# line of code. Returns breakpoint number or 0 if nonedef effective(file, line, frame):"""Determine which breakpoint for this file:line is to be acted upon.Called only if we know there is a breakpoint at this location. Returnthe breakpoint that was triggered and a boolean that indicates if it isok to delete a temporary breakpoint. Return (None, None) if there is nomatching breakpoint."""possibles = Breakpoint.bplist[file, line]for b in possibles:if not b.enabled:continueif not checkfuncname(b, frame):continue# Count every hit when bp is enabledb.hits += 1if not b.cond:# If unconditional, and ignoring go on to next, else breakif b.ignore > 0:b.ignore -= 1continueelse:# breakpoint and marker that it's ok to delete if temporaryreturn (b, True)else:# Conditional bp.# Ignore count applies only to those bpt hits where the# condition evaluates to true.try:val = eval(b.cond, frame.f_globals, frame.f_locals)if val:if b.ignore > 0:b.ignore -= 1# continueelse:return (b, True)# else:# continueexcept:# if eval fails, most conservative thing is to stop on# breakpoint regardless of ignore count. Don't delete# temporary, as another hint to user.return (b, False)return (None, None)# -------------------- testing --------------------class Tdb(Bdb):def user_call(self, frame, args):name = frame.f_code.co_nameif not name: name = '???'print('+++ call', name, args)def user_line(self, frame):import linecachename = frame.f_code.co_nameif not name: name = '???'fn = self.canonic(frame.f_code.co_filename)line = linecache.getline(fn, frame.f_lineno, frame.f_globals)print('+++', fn, frame.f_lineno, name, ':', line.strip())def user_return(self, frame, retval):print('+++ return', retval)def user_exception(self, frame, exc_stuff):print('+++ exception', exc_stuff)self.set_continue()def foo(n):print('foo(', n, ')')x = bar(n*10)print('bar returned', x)def bar(a):print('bar(', a, ')')return a/2def test():t = Tdb()t.run('import bdb; bdb.foo(10)')
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。