资讯动态

pytest 2.8.4 发布解析:deprecated_call、--pastebin 与收集鲁棒性的关键修复

发布时间:2026/9/14 9:01:49 来源:尧图企业网站定制
pytest 2.8.4 发布解析deprecated_call、--pastebin 与收集鲁棒性的关键修复【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytest本篇技术解读以官方发布公告 release-2.8.4.rst 为骨架结合 pytest 仓库当前源码与测试用例逐条剖析 2.8.4 修复的五个核心问题。读者将掌握pytest.deprecated_call()的两种使用形态与底层实现、--pastebin的完整工作链路、Python 3 与非 ASCII 输出的兼容处理、异常__getattr__对收集阶段的影响以及无测试运行摘要的生成机制并能用仓库中的测试用例验证每一项修复。版本概览一个即插即用的补丁版本pytest 2.8.4 是一个针对 2.8.x 分支的补丁版本。公告明确指出该版本与 2.8.2 完全向后兼容drop-in compatible用户无需修改任何测试代码即可升级。升级方式与所有 pytest 版本一致pip install -U pytest该版本没有引入新功能全部变更集中在三类问题上警告断言正确性、pastebin 上报链路、收集阶段的鲁棒性外加一处摘要输出修正与一批文档现代化。公告还特别强调pytest 自身使用超过 1100 个测试在多种解释器与平台上进行自测——这一自举传统在仓库中延续至今每个修复都带有对应的回归测试下文将逐一对应展示。修复一#1190 deprecated_call 在同模块多次触发时失效问题背景pytest.deprecated_call()用于断言某段代码会抛出DeprecationWarning、PendingDeprecationWarning或FutureWarning。在 2.8.4 之前存在一个隐蔽缺陷当被断言为已废弃的函数被同一模块中的另一个测试先行调用后deprecated_call()会错误地捕获不到警告导致断言失败。这一现象与 Pythonwarnings模块的默认过滤机制有关——带有default行为的警告过滤器会针对同一位置仅提示一次即__warningregistry__机制进行去重函数被提前调用后再次调用不再重新发出警告。修复后的实现当前仓库中deprecated_call()的实现位于 src/_pytest/recwarn.py其核心逻辑是dep_warnings (DeprecationWarning, PendingDeprecationWarning, FutureWarning) if func is None: return warns(dep_warnings, *args, **kwargs) with warns(dep_warnings): return func(*args, **kwargs)两种用法都会转入warns()后者在进入上下文时通过warnings.simplefilter(default)见同文件 recwarn.py重设过滤栈从而绕开同一位置只提示一次的去重影响保证无论目标函数此前是否已被调用deprecated_call()都能稳定捕获到警告。这正是 #1190 修复的实质。两种调用形态deprecated_call()支持上下文管理器与直接调用函数两种形态对应源码中的两个overload声明见 recwarn.pyimport warnings import pytest def api_call_v2(): warnings.warn(use v3 of this api, DeprecationWarning) return 200 # 形态一上下文管理器 with pytest.deprecated_call(): assert api_call_v2() 200 # 形态二直接调用返回被调用函数的返回值 ret pytest.deprecated_call(api_call_v2) assert ret 200 # 配合 match 参数做正则匹配 with pytest.deprecated_call(match^use v3 of this api$): api_call_v2()match参数接受字符串或编译后的re.Pattern用于对警告消息做正则断言见 recwarn.py 的 docstring 说明。回归测试证据仓库中的测试类TestDeprecatedCall见 testing/test_recwarn.py专门覆盖了此修复test_deprecated_call_modestest_recwarn.py参数化覆盖三种警告类型、两种调用形态以及**先调用函数再断言**call_f_firstTrue的场景注释明确指出ensure deprecated_call() can capture the warning even if it has already been triggered——这正是 #1190 的回归用例test_deprecated_call_no_warningtest_recwarn.py验证代码块未产生废弃警告时抛出No warnings of type (...)失败test_deprecated_call_specificitytest_recwarn.py验证对其他非废弃警告类型如UserWarning、RuntimeWarning不会被误捕获test_deprecated_call_preservestest_recwarn.py确保deprecated_call的执行不破坏warnings.filters与warnings.onceregistry的全局状态。修复二#1198 与 #1219 --pastebin 在 Python 3 上的兼容性--pastebin是 pytest 内置的故障上报功能将失败详情或整个会话日志上传到在线 paste 服务当前实现为bpa.st并输出可分享的 URL。2.8.4 修复了它在 Python 3 上的两个问题Python 3 下完全不可用#1198以及捕获输出含非 ASCII 字符时上报内容损坏#1219。插件实现全貌pastebin 功能由独立插件模块 src/_pytest/pastebin.py 承载其工作链路如下注册选项pytest_addoptionpastebin.py在 terminal reporting 分组下注册--pastebin选项取值限定为failed或allpytest --pastebinfailed # 仅上报失败用例详情 pytest --pastebinall # 上报整个会话的终端输出会话日志采集--pastebinallpytest_configurepastebin.py通过临时文件tempfile.TemporaryFile(wb)建立二进制日志缓冲并用tee_write包装TerminalReporter的写方法将终端输出以 UTF-8 编码后同步写入缓冲——if isinstance(s, str): s s.encode(utf-8)这一行正是 #1219 的关键修复点旧版本直接按字节拼接遇到非 ASCII 字符如中文、emoji会产生UnicodeEncodeError或乱码。会话结束时上报pytest_unconfigurepastebin.py读取缓冲内容调用create_new_paste()上传输出pastebin session-log: URL。仅上报失败--pastebinfailedpytest_terminal_summarypastebin.py遍历terminalreporter.stats[failed]中的失败报告取最后一条 traceback 的文件位置信息作为标题将失败详情逐条上传输出位置信息 -- URL。上传细节create_new_paste()pastebin.py使用标准库urllib.request.urlopen向https://bpa.stPOSTurlencode编码的数据含code、lexertext、expiry1week参数并从响应中正则提取/raw/链接拼接出/show/id形式的最终 URL请求失败HTTPError/OSError时返回bad response: ...错误信息而非抛出异常。Python 3 兼容性#1198#1198 的根因是旧实现对 Python 3 的字节/字符串模型bytes vs str处理不当。修复后整个链路的边界清晰终端输出统一按str处理写入缓冲前显式encode(utf-8)上传时用urlencode(params).encode(ascii)序列化请求体读取响应时decode(utf-8)全程显式编解码避免隐式类型错误。这一边界约定在源码注释中也有体现# pastebin file will be UTF-8 encoded binary file.pastebin.py。回归测试证据测试文件 testing/test_pastebin.py 中test_non_ascii_paste_texttest_pastebin.py#1219 的直接回归用例构造包含 emoji 的断言失败assert ☺ 1运行--pastebinall后断言终端仍输出*assert ☺ 1*且 pastebin 内容经decode(utf-8)后匹配预期——验证非 ASCII 内容全程无损测试通过pastebinlistfixture 拦截真实的urllib.request.urlopen调用mocked_urlopen/mocked_urlopen_invalid见 test_pastebin.py在不依赖外网的前提下验证上传内容与返回 URL 解析逻辑。需要说明在当前仓库中--pastebin已被标记为弃用pytest_configure中通过config.issue_config_time_warning(PASTEBIN, 2)发出弃用警告见 pastebin.py测试test_deprecated断言输出包含 The --pastebin option is deprecated见 test_pastebin.py但 2.8.4 修复的兼容性逻辑仍是其当前实现的基础。修复三#1204 收集阶段遭遇刁钻getattr时崩溃pytest 在收集阶段会通过反射dir()、getattr等探查测试类与模块的属性。若类定义了行为异常的__getattr__例如对任意属性名都返回函数或触发异常旧版本会将其误判为存在__test__标志或直接抛出收集错误导致测试收集失败。这是 #1204 修复的问题。当前实现与测试仓库中test_class_with_nasty_getattrtesting/python/integration.py记录了修复动机并明确引用 issue 链接With a custom__getattr__which e.g. returns a function (like with a RPC wrapper), we shouldnt assume this meant__test__ True.即一个返回函数的__getattr__不应被解释为__test__ True。同类问题在收集测试中还有多处覆盖test_issue1035_obj_has_getattrtesting/python/collect.py对象__getattr__对任意属性名返回True验证收集不崩溃testing/python/collect.py类__getattr__返回非整数对象时收集仍正常。从当前源码看pytest 在属性探查上采用防御性策略通过安全的内省方式判定测试类/测试函数对__getattr__的返回结果做类型约束校验而非直接信任属性名与返回值。这类防护持续演进例如 testing/python/integration.py 的用例至今仍是收集相关回归测试的一部分。修复四无测试运行时摘要输出修正2.8.4 还修复了没有测试运行时的会话摘要显示问题。此前在某些空运行场景下摘要可能显示空白或格式异常修复后统一输出no tests ran。当前实现位于终端摘要构建逻辑中src/_pytest/terminal.pyif not parts: parts [(no tests ran, {_color_for_type_default: True})]当会话没有任何可统计的结果类型无 passed/failed/skipped 等计数时摘要部分回退为no tests ran并套用默认颜色标记保证终端输出始终完整、格式稳定。这一行为与--collect-only、空目录、全部用例被 skip 等场景下的会话结束输出直接相关。修复五面向good practices的文档现代化2.8.4 附带了一批文档现代化改动主题是推广 pytest 的最佳实践good practices。这一方向在仓库中持续沉淀当前doc/en/目录下的 goodpractices.rst 已成为独立的 Explanation 章节系统讲解推荐的目录结构src布局、pytest.ini/tox.ini等配置载体、以及conftest.py的作用域约定。对升级 2.8.4 的团队而言配合这些实践可将项目测试组织方式规范化。如何验证这些修复在当前仓库中可直接运行对应回归测试验证全部修复点# 验证 deprecated_call 相关修复#1190 python -m pytest testing/test_recwarn.py -k DeprecatedCall # 验证 pastebin 兼容性修复#1198 / #1219 python -m pytest testing/test_pastebin.py # 验证收集鲁棒性修复#1204 python -m pytest testing/python/integration.py -k nasty_getattr python -m pytest testing/python/collect.py -k getattr # 验证no tests ran摘要 python -m pytest testing/test_terminal.py -k no tests ran这些测试不仅证明了 2.8.4 修复的正确性也展示了 pytest 社区每个 bug 必有回归测试的工程惯例——这也是公告中pytest 用 1100 自测覆盖自身的实践延续。小结pytest 2.8.4 虽是小版本却体现了成熟测试框架对细节的执着deprecated_call()在跨测试调用场景下的正确性、--pastebin在 Python 3 下的字节边界处理、异常__getattr__对收集器的影响、以及空运行摘要的稳定性每一项都有明确的 issue、源码实现与回归测试三方对应。升级命令仅需pip install -U pytest且与 2.8.2 完全兼容是低风险高收益的补丁版本。【免费下载链接】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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价