十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

pytest 断言输出截断机制解析:大型 diff 的惰性构建与截断预算

pytest 断言输出截断机制解析:大型 diff 的惰性构建与截断预算 pytest 断言输出截断机制解析大型 diff 的惰性构建与截断预算【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest本文基于 pytest 变更日志 changelog/14523.improvement.rst 中记录的断言比较输出改进展开大型断言比较 diff 现在按截断预算“惰性构建”不再把整个巨型 diff 完整格式化后再截断作为附带影响截断页脚也不再报告被隐藏行的确切数量。读完本文你能理解 pytest 断言解释assertion explanation从生成到截断的完整数据流、truncation_limit_lines/truncation_limit_chars两个 ini 选项的生效条件与默认值以及页脚文案变化的底层原因。变更条目说的是什么该条变更日志原文仅四行但包含两个可验证的行为变化大型断言比较 diff 惰性构建并受截断预算约束lazily built and capped to the truncation budget——巨型 diff 不再“先完整格式化、再被截断”即不再做大量注定被丢弃的格式化工作截断页脚不再报告被隐藏行的确切数量——因为输出流在到达预算上限处就被切断格式化器根本不知道后面还有多少行。这一改进直接作用于assert失败时 pytest 生成的比较说明是 src/_pytest/assertion/truncate.py 所在模块的核心职责范围。截断何时生效三个开关与默认预算截断决策集中在 truncate.py 的_get_truncation_parameters()中满足下列任一条件即不截断断言输出冗长度达到 2 级及以上即--verbosity2等价于-vv通过config.get_verbosity(Config.VERBOSITY_ASSERTIONS)读取运行在 CI 环境中通过 src/_pytest/compat.py 的running_on_ci()检测truncation_limit_lines与truncation_limit_chars两个 ini 选项同时被显式设为 0。两项 ini 选项在 src/_pytest/assertion/init.py 中注册缺省时回落到 TruncationBudget 的默认值ini 选项默认值取值 0 的含义truncation_limit_lines8 行不按行数截断truncation_limit_chars640即 8 × 80不按字符数截断TruncationBudget是一个不可变 dataclassmax_lines/max_chars两个维度独立生效达到任一上限即停止输出NO_TRUNCATION_BUDGET两个值均为 0表示无上限被用作各比较函数的默认参数。官方文档对这两个选项的说明见 doc/en/reference/reference.rst。惰性构建materialize_with_truncation改进的核心是 materialize_with_truncation()断言比较函数现在以惰性迭代器逐行 yield的形式产出解释文本而不是先拼好完整列表。该函数从迭代器中逐行拉取并累计字符数一旦越过阈值立即break迭代器剩余部分直接被丢弃、不再消费for line in lines: buffered.append(line) char_count len(line) if line_cap is not None and len(buffered) line_cap: break if budget.max_chars 0 and char_count tolerable_max_chars: break else: # 迭代器在限额内耗尽——无需截断 return buffered有两个细节值得注意对应 truncate.py 的模块常量截断会追加页脚最后一行加...、空行、提示消息共TRUNCATION_FOOTER_LINES 2行、TRUNCATION_FOOTER_CHARS len(...) len(TRUNCATION_MSG)个字符的额外开销。因此判断是否溢出时允许正文超出原始预算一个“页脚代价”tolerable_max_chars budget.max_chars TRUNCATION_FOOTER_CHARS行数上限为max_lines 2避免“差一点就装得下”的输出被硬生生切开只为腾出页脚空间行数上限取的是budget.max_lines 2 1即比保留上限多拉一行以检测溢出但绝不多物化。真正需要截断时交给 _truncate_explanation()先按行数切再按字符数补切_truncate_by_char_count给保留的最后一行追加...并在末尾加上...Full output truncated, use -vv to show注意这里就是变更日志提到的第二个行为变化TRUNCATION_MSG只提示“完整输出已截断用-vv查看”不再附带“还有 N 行被隐藏”这类精确计数——因为惰性拉取在越限处就中止了后方的行数根本无法统计。预算如何下传比较器也不再格式化被丢弃的内容只靠消费端截断还不够改进的另一半是让上游按预算限量生产。在 pytest_assertrepr_compare() 中当判定要截断时会构造一个“带页脚余量的截断预算”行数上限加 3、字符上限加页脚字符数并传给util.assertrepr_compare()。这个truncation_budget参数沿调用链继续下传到各个比较实现文本 diffcompare_text.py 中ndiff的输入先经_cap_ndiff_input()裁剪——先按字符数切片约束单行超长文本其行内 diff 复杂度是 O(len²)再按行数切片约束多行文本。源码注释明确说明设置预算时截断后呈现的头部可能与“无上限完整 diff”的头部不同序列比较_compare_sequence.py 接收max_lines/max_chars只格式化预算内的元素映射比较_compare_mapping.py 同样按预算限制多余项extra items的格式化数量。也就是说从源码结构看整条链路形成了“比较器按预算限量产出 → 物化器按预算限量拉取”的双层约束巨型断言失败比如对比两个几千行的字符串或长列表时pytest 只为最终会显示的那部分做 saferepr、diff 高亮等格式化工作而不是像过去那样完整格式化后再丢弃尾部。这正是变更日志中“so a huge diff is no longer formatted in full just to be truncated”的实现依据。此外pytest_runtest_protocol 中的 callbinrepr() 对插件自定义的pytest_assertrepr_comparehook 返回值也统一走materialize_with_truncation()因此第三方插件产出的大型解释同样受同一套惰性截断保护。验证与实测行为仓库的测试用例印证了新的页脚格式例如 testing/test_assertion.py 中预期输出包含E ...Full output truncated, use -vv to showFull output truncated这一断言在 testing/test_assertion.py 与 testing/python/approx.py 中多处出现覆盖了默认预算、自定义 ini 预算等场景。实际操作层面验证这一行为的完整步骤写一个对比两个超长序列或长字符串的断言使其失败默认情况下不加-vv、非 CI失败输出最多约 8 行 / 640 字符末尾出现...Full output truncated, use -vv to show且不再出现“隐藏 N 行”的计数在pytest.ini/pyproject.toml的[tool.pytest.ini_options]中设置truncation_limit_lines/truncation_limit_chars调整预算两者均设为0则完全关闭截断加-vv或在 CI 环境运行则不截断查看完整 diff。小结这条改进的本质是把截断从“格式化之后的裁剪”前移为“格式化过程中的限量”比较器按预算产出、物化器按预算拉取两处都以 truncate.py 中的预算参数与页脚常量为准。对用户的直接影响只有两条——超大 diff 场景下断言解释的生成开销下降以及截断页脚从“精确隐藏行数”变为通用的-vv提示。相关实现可沿 src/_pytest/assertion/truncate.py截断与预算、src/_pytest/assertion/_typing.pyTruncationBudget定义与默认值、src/_pytest/assertion/compare_text.pyndiff 输入裁剪三个文件继续深入。【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表