首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

pytest的内置插件盘点31. unraisableexception | 对接python和pytest底层收集特殊异常

本文系《pytest源码剖析》系列内容

31. unraisableexception

插件路径:_pytest.unraisableexception

实现的 hook

调用的 hook

定义的 fixture

插件功能

创建上下文管理器catch_unraisable_exception

并在在以下 hook 包装器中使用:

pytest_runtest_setup

pytest_runtest_call

pytest_runtest_teardown

代码片段

def unraisable_exception_runtest_hook() -> Generator[None, None, None]: with catch_unraisable_exception() as cm: yield if cm.unraisable: print('xxxxxxxxx') if cm.unraisable.err_msg is not None: err_msg = cm.unraisable.err_msg else: err_msg = "Exception ignored in" msg = f"{err_msg}: {cm.unraisable.object!r}\n\n" msg += "".join( traceback.format_exception( cm.unraisable.exc_type, cm.unraisable.exc_value, cm.unraisable.exc_traceback, ) ) warnings.warn(pytest.PytestUnraisableExceptionWarning(msg))

通过上下文管理器的方式,收集无法引发的异常,并发出警告

简评

unraisablehook是 python 3.8 新增的一个钩子,在 python 遇到” 无法引发的异常 “时自动调用。

通过设置该 hook,可以自助处理“无法引发的异常 ”。

本插件正是让 pytest 设置了这个 python 的钩子,在遇到这些情况时发出警告

...

所谓“无法引发的异常 ”(或可译作“未抛出的异常”?)是一种在 Python 无法将其报告给调用者时发生的错误

例如:对象终结器错误 (__del__())、弱引用回调失败、GC 收集期间出错

请看这样的代码

assert False

这是一个引发【断言异常】的代码,引起引发了一次,python 退出代码为 1

Traceback (most recent call last): File "E:\PyProject\pytest_7.2.x\aaaaa.py", line 1, in assert FalseAssertionError

Process finished with exit code 1

如果把它放在类的__del__方法中:

class A:

def __del__(self): assert False

A()

执行结果

Exception ignored in: <function A.__del__ at 0x000001DE612D53A0>Traceback (most recent call last): File "E:\PyProject\pytest_7.2.x\aaaaa.py", line 4, in __del__ assert FalseAssertionError:

Process finished with exit code 0

它引发异常了吗?

没有。

证据有二:

退出代码为 0 (表示正常退出)

输出了一行字Exception ignored异常被忽略

这个异常,就是无法引发的异常

...

这样的异常不能被处理(或记录)吗?

当然可以 ,python 3.8 新增的 hookunraisablehook就是为此而生。

接下来我们实现这个 hook

import sys

def sanmu_funcs(unraisable: "sys.UnraisableHookArgs"): # 创建函数处理 print('异常类型', unraisable.exc_type) print('引发位置', unraisable.exc_traceback.tb_frame.f_code) print('局部变量', unraisable.exc_traceback.tb_frame.f_locals)

sys.unraisablehook = sanmu_funcs # 注册钩子

执行结果

异常类型<class >引发位置 <\code object __del__ at 0x000002A16F42DE40, file "D:\pytest_7.2.x\aaa.py", line 16>局部变量 {'self': <__main__.A object at 0x000002A16F56DC10>}

Process finished with exit code 0

...

本插件通过上下文管理器的方式,分别在用例执行的三个阶段进行处理:

setup

call

teardown

用例执行阶段出现了了“无法引发的异常”,会在pytest运行结束后统一发出警告

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OV0MAldGToOCJ702rD7fXJXQ0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券