bdb — 调试器框架

源代码: Lib/bdb.py


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

定义了以下异常

exception bdb.BdbQuit

Bdb 类引发的异常,用于退出调试器。

bdb 模块还定义了两个类

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

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

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

创建断点时,其关联的 file name 应该采用规范形式。如果定义了 funcname,则当执行该函数的第一行时,将计算断点 hitconditional 断点始终计算 hit

Breakpoint 实例具有以下方法

deleteMe()

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

enable()

将断点标记为启用。

disable()

将断点标记为禁用。

bpformat()

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

  • 断点编号。

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

  • 文件/行位置。

  • 断点条件。

  • 要忽略的次数。

  • 命中的次数。

3.2 版本新增。

bpprint(out=None)

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

Breakpoint 实例具有以下属性

file

Breakpoint 的文件名。

line

fileBreakpoint 的行号。

temporary

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

cond

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

funcname

定义是否在进入函数时命中 Breakpoint 的函数名。

enabled

如果 Breakpoint 已启用,则为 True

bpbynumber

Breakpoint 单个实例的数字索引。

bplist

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

ignore

忽略 Breakpoint 的次数。

hits

Breakpoint 被命中的次数计数。

class bdb.Bdb(skip=None)

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

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

如果给定 skip 参数,它必须是 glob 样式的模块名称模式的可迭代对象。调试器不会步入与这些模式之一匹配的模块中产生的帧。一个帧是否被认为起源于某个模块,由帧全局变量中的 __name__ 决定。

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

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

canonic(filename)

返回 *filename* 的规范形式。

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

reset()

使用准备开始调试的值设置 botframe, stopframe, returnframequitting 属性。

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)

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

set_trace([frame])

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

在 3.13 版本中变更: set_trace() 将立即进入调试器,而不是在下一行要执行的代码处进入。

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)

删除 filenamelineno 中的断点。如果没有设置断点,则返回错误消息。

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)

返回 filenamelineno 的所有断点,如果没有设置,则返回空列表。

get_file_breaks(filename)

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

get_all_breaks()

返回已设置的所有断点。

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

get_stack(f, t)

返回堆栈跟踪中的 (帧, 行号) 元组列表和一个大小。

最近调用的帧在列表的末尾。大小是调试器被调用时所在帧下方的帧数。

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() 函数执行的表达式。globalslocals 的含义与 run() 中相同。

runctx(cmd, globals, locals)

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

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

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

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

bdb.checkfuncname(b, frame)

如果应该在此处中断,则返回 True,具体取决于 Breakpoint b 的设置方式。

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

bdb.effective(file, line, frame)

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

活动断点bplist 中 ( fileline )(必须存在)的第一个条目,该条目是 enabled,对于该条目,checkfuncname() 为真,并且既没有假的 condition,也没有正的 ignore 计数。当 cond 无法计算时,标志(意味着应删除临时断点)才为 False(在这种情况下,ignore 计数将被忽略)。

如果不存在这样的条目,则返回 (None, None)

bdb.set_trace()

从调用者的框架开始使用 Bdb 实例进行调试。