bdb — 调试器框架

源代码: Lib/bdb.py


bdb 模块处理基本的调试器功能,例如设置断点或通过调试器管理执行。

定义了以下异常

异常 bdb.BdbQuit

Bdb 类为退出调试器而引发的异常。

bdb 模块还定义了两个类

bdb.Breakpoint(self, file, line, temporary=False, cond=None, funcname=None)

此类实现临时断点、忽略计数、禁用和(重新)启用以及条件。

断点通过名为 bpbynumber 的列表按编号索引,并通过 (file, line) 对通过 bplist 索引。前者指向 Breakpoint 类的单个实例。后者指向此类实例的列表,因为每行可能有多个断点。

创建断点时,其关联的 文件名 应采用规范形式。如果定义了 funcname,则在执行该函数的第一行时,将计算断点 命中 次数。条件 断点始终计算 命中 次数。

Breakpoint 实例具有以下方法

deleteMe()

从与文件/行关联的列表中删除断点。如果它是该位置的最后一个断点,它还会删除文件/行的条目。

enable()

将断点标记为启用。

disable()

将断点标记为禁用。

bpformat()

返回一个字符串,其中包含有关断点的所有信息,格式精美

  • 断点编号。

  • 临时状态(删除或保留)。

  • 文件/行位置。

  • 中断条件。

  • 要忽略的次数。

  • 命中次数。

3.2 版新增。

bpprint(out=None)

bpformat() 的输出打印到文件 out,如果它是 None,则打印到标准输出。

Breakpoint 实例具有以下属性

file

Breakpoint 的文件名。

line

Breakpointfile 中的行号。

temporary

如果 (file, line) 处的 Breakpoint 是临时的,则为 True

cond

用于评估 (file, line) 处的 Breakpoint 的条件。

funcname

函数名称,用于定义在进入函数时是否命中 Breakpoint

enabled

如果 Breakpoint 已启用,则为 True

bpbynumber

Breakpoint 的单个实例的数字索引。

bplist

由 (file, line) 元组索引的 Breakpoint 实例字典。

ignore

要忽略 Breakpoint 的次数。

hits

Breakpoint 被命中的次数计数。

bdb.Bdb(skip=None)

Bdb 类充当通用的 Python 调试器基类。

此类负责处理跟踪工具的细节;派生类应该实现用户交互。标准调试器类 (pdb.Pdb) 是一个例子。

skip 参数(如果给出)必须是 glob 风格的模块名称模式的可迭代对象。调试器不会进入源自与其中一种模式匹配的模块的帧。一个帧是否被认为源自某个模块是由帧全局变量中的 __name__ 决定的。

在 3.1 版更改: 添加了 skip 参数。

以下 Bdb 的方法通常不需要重写。

canonic(filename)

返回 filename 的规范形式。

对于真实的文件名,规范形式是依赖于操作系统的、大小写规范化绝对路径。带有尖括号的 filename(例如在交互模式下生成的 "<stdin>")将保持不变。

reset()

使用准备开始调试的值设置 botframestopframereturnframequitting 属性。

trace_dispatch(frame, event, arg)

此函数被安装为调试帧的跟踪函数。它的返回值是新的跟踪函数(在大多数情况下,也就是它本身)。

默认实现根据即将执行的事件类型(作为字符串传递)决定如何调度帧。 event 可以是以下之一

  • "line":即将执行一行新代码。

  • "call":即将调用一个函数,或进入另一个代码块。

  • "return":一个函数或其他代码块即将返回。

  • "exception":发生了异常。

  • "c_call":即将调用一个 C 函数。

  • "c_return":一个 C 函数已返回。

  • "c_exception":一个 C 函数引发了异常。

对于 Python 事件,将调用专门的函数(见下文)。对于 C 事件,不采取任何操作。

arg 参数取决于先前的事件。

有关跟踪函数的更多信息,请参阅 sys.settrace() 的文档。有关代码和帧对象的更多信息,请参阅 标准类型层次结构

dispatch_line(frame)

如果调试器应该在当前行停止,则调用 user_line() 方法(该方法应该在子类中被重写)。如果设置了 quitting 标志(可以从 user_line() 中设置),则引发 BdbQuit 异常。返回对 trace_dispatch() 方法的引用,以便在该作用域中进行进一步跟踪。

dispatch_call(frame, arg)

如果调试器应该在此函数调用时停止,则调用 user_call() 方法(该方法应该在子类中被重写)。如果设置了 quitting 标志(可以从 user_call() 中设置),则引发 BdbQuit 异常。返回对 trace_dispatch() 方法的引用,以便在该作用域中进行进一步跟踪。

dispatch_return(frame, arg)

如果调试器应该在此函数返回时停止,则调用 user_return() 方法(该方法应该在子类中被重写)。如果设置了 quitting 标志(可以从 user_return() 中设置),则引发 BdbQuit 异常。返回对 trace_dispatch() 方法的引用,以便在该作用域中进行进一步跟踪。

dispatch_exception(frame, arg)

如果调试器应该在此异常处停止,则调用 user_exception() 方法(该方法应该在子类中被覆盖)。如果设置了 quitting 标志(可以从 user_exception() 中设置),则引发 BdbQuit 异常。返回对 trace_dispatch() 方法的引用,以便在该作用域中进行进一步跟踪。

通常,派生类不会覆盖以下方法,但如果它们想重新定义停止和断点的定义,则可以覆盖。

is_skipped_line(module_name)

如果 *module_name* 与任何跳过模式匹配,则返回 True

stop_here(frame)

如果 *frame* 位于堆栈中起始帧的下方,则返回 True

break_here(frame)

如果此行存在有效断点,则返回 True

检查是否存在行断点或函数断点,以及该断点是否有效。根据 effective() 中的信息删除临时断点。

break_anywhere(frame)

如果 *frame* 的文件名存在任何断点,则返回 True

派生类应该覆盖这些方法以获得对调试器操作的控制。

user_call(frame, argument_list)

如果断点可能在被调用函数内部停止,则从 dispatch_call() 调用。

*argument_list* 不再使用,并且始终为 None。保留该参数是为了向后兼容。

user_line(frame)

stop_here()break_here() 返回 True 时,从 dispatch_line() 调用。

user_return(frame, return_value)

stop_here() 返回 True 时,从 dispatch_return() 调用。

user_exception(frame, exc_info)

stop_here() 返回 True 时,从 dispatch_exception() 调用。

do_clear(arg)

处理当断点是临时断点时如何删除它。

此方法必须由派生类实现。

派生类和客户端可以调用以下方法来影响步进状态。

set_step()

执行一行代码后停止。

set_next(frame)

在给定帧内或下方停止。

set_return(frame)

从给定帧返回时停止。

set_until(frame, lineno=None)

当到达 *lineno* 大于当前行的行时,或从当前帧返回时停止。

set_trace([frame])

从 *frame* 开始调试。如果未指定 *frame*,则从调用者的帧开始调试。

set_continue()

仅在断点处或完成时停止。如果没有断点,则将系统跟踪函数设置为 None

set_quit()

quitting 属性设置为 True。这会在下次调用 dispatch_*() 方法之一时引发 BdbQuit

派生类和客户端可以调用以下方法来操作断点。如果出现问题,这些方法将返回一个包含错误消息的字符串;如果一切正常,则返回 None

set_break(filename, lineno, temporary=False, cond=None, funcname=None)

设置一个新的断点。如果作为参数传递的 *filename* 不存在 *lineno* 行,则返回一条错误消息。*filename* 应该采用规范形式,如 canonic() 方法中所述。

clear_break(filename, lineno)

删除 *filename* 和 *lineno* 中的断点。如果未设置,则返回错误消息。

clear_bpbynumber(arg)

删除 Breakpoint.bpbynumber 中索引为 *arg* 的断点。如果 *arg* 不是数字或超出范围,则返回错误消息。

clear_all_file_breaks(filename)

删除 *filename* 中的所有断点。如果未设置,则返回错误消息。

clear_all_breaks()

删除所有现有的断点。如果未设置,则返回错误消息。

get_bpbynumber(arg)

返回由给定数字指定的断点。如果 *arg* 是字符串,它将被转换为数字。如果 *arg* 是非数字字符串,或者给定的断点从未存在或已被删除,则会引发 ValueError

3.2 版新增。

get_break(filename, lineno)

如果 *filename* 中的 *lineno* 处存在断点,则返回 True

get_breaks(filename, lineno)

返回 *filename* 中 *lineno* 处的所有断点,如果未设置,则返回空列表。

get_file_breaks(filename)

返回 *filename* 中的所有断点,如果未设置,则返回空列表。

get_all_breaks()

返回所有已设置的断点。

派生类和客户端可以调用以下方法来获取表示堆栈跟踪的数据结构。

get_stack(f, t)

返回堆栈跟踪中的 (frame, lineno) 元组列表和大小。

最近调用的帧在列表的最后。大小是调用调试器的帧下方帧的数量。

format_stack_entry(frame_lineno, lprefix=': ')

返回一个包含堆栈条目信息的字符串,该条目是一个 (frame, lineno) 元组。返回的字符串包含

  • 包含该帧的规范文件名。

  • 函数名称或 "<lambda>"

  • 输入参数。

  • 返回值。

  • 代码行(如果存在)。

客户端可以调用以下两种方法,使用调试器来调试作为字符串给出的 语句

run(cmd, globals=None, locals=None)

调试通过 exec() 函数执行的语句。*globals* 默认为 __main__.__dict__,*locals* 默认为 *globals*。

runeval(expr, globals=None, locals=None)

调试通过 eval() 函数执行的表达式。*globals* 和 *locals* 的含义与 run() 中的相同。

runctx(cmd, globals, locals)

为了向后兼容。调用 run() 方法。

runcall(func, /, *args, **kwds)

调试单个函数调用,并返回其结果。

最后,模块定义了以下函数

bdb.checkfuncname(b, frame)

根据设置 Breakpoint *b* 的方式,如果我们应该在此处中断,则返回 True

如果它是通过行号设置的,它会检查 b.line 是否与 *frame* 中的相同。如果断点是通过 函数名 设置的,我们必须检查我们是否在正确的 *frame*(正确的函数)中,以及我们是否在其第一个可执行行上。

bdb.effective(file, line, frame)

返回 (活动的断点,删除临时标志)(None, None) 作为要操作的断点。

活动断点是 (file, line)(必须存在)的 bplist 中的第一个条目,该条目已启用checkfuncname() 为真,并且既没有 false condition 也没有正 ignore 计数。 flag 表示应删除临时断点,仅当 cond 无法评估时才为 False(在这种情况下,将忽略 ignore 计数)。

如果不存在此类条目,则返回 (None, None)

bdb.set_trace()

使用调用方帧中的 Bdb 实例开始调试。