DEBUG.WIKI
ZgoCloud:多地区部署,按需选节点;日本、美国、香港、德国
搬瓦工;先看线路,再选 VPS;CN2 GIA · 对应线路套餐;查看线路 →
V.PS:让项目靠近用户,亚太、欧洲、北美 KVM VPS

pytest recwarn.pop() 取到最后一条警告,检查类别选择

pytest 9.1.1 的宽泛 pop 会让后出现的同级警告覆盖先前候选。时序断言可直接检查记录列表,明确类别可精确 pop,同时保留父子类别的原有选择要求。

测试依次发出 UserWarning、RuntimeWarning 和 DeprecationWarning,recwarn.pop() 却取走了最后一个,导致 assert 'third' == 'first'。这时记录器并没有倒序收集所有警告,要检查 pop() 在宽泛类别下的选择规则。

pytest 9.1.1 的正式实现仍有这条分支:候选警告属于请求类别时,如果它不是当前候选类别的子类,就替换当前候选。互不继承的同级类别也满足这个条件,因此后出现的类别会覆盖先前选择。这与文档所说的“第一个符合条件的记录”存在差异。

需要检查发出顺序时,直接读取记录序列

下面的测试说明如何检查三条警告的完整顺序,不依赖宽泛 pop(Warning) 的选择结果:

import warnings


def test_warning_order(recwarn):
    warnings.warn("first", UserWarning)
    warnings.warn("second", RuntimeWarning)
    warnings.warn("third", DeprecationWarning)

    recorded = list(recwarn)
    assert [item.category for item in recorded] == [
        UserWarning, RuntimeWarning, DeprecationWarning,
    ]
    assert [str(item.message) for item in recorded] == [
        "first", "second", "third",
    ]

这里检查的是应用实际需要保护的时序,读取列表不会从记录器里移除项目。真实测试应保留自己的预期类别、消息和数量,不要为了让断言通过把预期顺序改成错误 pop() 的输出。

如果只关心一个明确类别,可以调用 recwarn.pop(UserWarning);遇到完全相同的类别时,当前实现会立即返回最早的精确匹配。若记录里只有它的子类,仍会进入继承关系选择,不能把所有父类参数都当成简单的先进先出队列。

警告继承优先与时间顺序是两个要求

pop() 原本还要在父子类别同时符合条件时避免优先取子类,这不是普通列表的无条件 pop(0)。不要直接改 pytest 私有 _list 或在安装目录替换整个循环;那可能修好同级类别时序,却破坏已有的父子类别测试。

保留失败时的完整警告序列,分别覆盖精确类别、互不相关的类别、父子类别和没有匹配项的情况。验收还要确认过滤配置没有提前屏蔽本应记录的警告。后续依赖更新后,先对照这些场景复查,再决定是否改回宽泛 pop();仅看到一次断言成功不能证明全部继承语义都相同。