pytest 6.2.1 发布解读:bug 修复版本中的两个关键修复(approx 数组协议回归与 Windows UNC 导入路径)
pytest 6.2.1 发布解读bug 修复版本中的两个关键修复approx 数组协议回归与 Windows UNC 导入路径【免费下载链接】pytestThe pytest framework makes it easy to write small tests, yet scales to support complex functional testing项目地址: https://gitcode.com/GitHub_Trending/py/pytestpytest 6.2.1 是 pytest 官方于 2020 年 12 月 15 日发布的一个纯 bug 修复版本bug-fix release作为 6.2.0 的 drop-in replacement可直接替换安装。本文基于本仓库中的发布公告 release-6.2.1.rst 与完整变更日志 changelog.rst 展开深入解析该版本修复的两个核心问题——approx对数组协议array protocol类对象的比较回归、以及 Windows UNC 路径下测试模块导入时报ImportPathMismatchError的缺陷并结合仓库源码与测试用例说明其底层原理。读完本文你将理解这两个 bug 的成因、修复思路以及如何验证与规避类似问题。版本概况与升级方式本仓库的发布公告文档 release-6.2.1.rst 明确指出pytest 6.2.1 是一个 bug-fix release且是 6.2.0 的直接替代版本升级不会带来破坏性变更。升级命令非常简单pip install --upgrade pytest该版本的完整变更日志记录在仓库文档 changelog.rst 中标题为 pytest 6.2.1 (2020-12-15)其中共包含两项 Bug Fixes:issue:7678修复在 Windows 上通过 UNC 挂载路径UNC mounted path加载宿主机器上编译文件时误抛ImportPathMismatchError的问题。:issue:8132修复approx的回归问题——6.2.0 中approx对非数值类型不再抛出TypeError而是回退到普通比较但对于 TensorFlowtf.DeviceArray等数组类对象6.2.0 开始反而比较失败。两项修复虽然看似独立但都指向 pytest 内部两个核心机制测试模块导入import_path与近似值比较approx。下面逐一深入。修复一Windows UNC 路径下的 ImportPathMismatchError问题背景pytest 在收集测试文件时会通过import_path()函数将测试模块导入 Python。为了确保导入的模块与磁盘上的文件对应一致pytest 会在导入后校验模块的__file__属性与实际路径是否匹配不一致时抛出ImportPathMismatchError。该异常定义在 pathlib.py 中class ImportPathMismatchError(ImportError): Raised on import_path() if there is a mismatch of __file__s. This can happen when import_path is called multiple times with different filenames that has the same basename but reside in packages (for example /tests1/test_foo.py and /tests2/test_foo.py). 从源码注释可以看到该异常原本设计用于捕获“不同目录下存在同名测试模块”导致的模块名冲突场景。但在 6.2.1 之前的某些 Windows 环境下宿主机器上编译的.pyc缓存文件从 UNC 挂载路径加载时路径规范化normalization的结果可能与原始路径不一致导致 pytest 误判为路径不匹配而抛出该异常进而导致测试收集失败。导入机制与三种模式修复的核心围绕 import_path() 展开。该函数支持三种导入模式ImportMode见 pathlib.py模式说明prepend将包含被测模块或包的目录置于sys.path开头后再以importlib.import_module导入append与prepend类似但目录被追加到sys.path末尾若尚未在路径中importlib使用importlib提供的更细粒度机制导入完全不改动sys.path从而允许在不同位置存在同名测试模块从源码看ImportPathMismatchError只在prepend和append两种模式下抛出见 pathlib.py 中 Only raised inprependandappendmodes 的说明因为这两种模式依赖模块在sys.modules中的唯一名称一旦磁盘路径与模块__file__对不上就说明存在同名冲突。而importlib模式为每个模块基于root锚点生成唯一名称天然规避了该问题。pytest 在 python.py 中导入了ImportPathMismatchError并在收集测试模块时捕获处理python.py。6.2.1 的修复即针对import_path内部对路径比较逻辑的校正使 UNC 路径下规范化后的__file__不再触发误报。规避建议如果你在 Windows 上通过 UNC 挂载路径运行 pytest 且遇到此类收集异常可以升级到 6.2.1 或更高版本本修复已包含或在pytest.ini/pyproject.toml中为收集阶段显式指定导入模式例如使用importlib模式# pytest.ini [pytest] consider_namespace_packages true说明importlib模式是避免同名模块冲突最彻底的方式也是 pytest 后续版本演进的方向。修复二approx 对数组协议类对象的比较回归问题成因approx是 pytest 内置的浮点数近似比较工具。6.2.0 之前像tf.DeviceArray这类既不属于 Python 标准数值类型层级、也不继承自numpy.ndarray的数组类对象会“落入”标量scalar分支恰好能在单元素场景下与标量正确比较6.2.0 调整了类型分发逻辑后这类对象既不能走标量分支也没有被当作 numpy 数组处理导致比较失败见 changelog.rst。修复方案识别数组协议6.2.1 的修复方案是只要对象暴露了数组协议array protocol且不是标量就将其转换为numpy.ndarray再参与比较。这一逻辑实现在 approx.py 的_as_numpy_array()辅助函数中def _as_numpy_array(obj: object) - ndarray | None: Return an ndarray if the given object is implicitly convertible to ndarray, and numpy is already imported, otherwise None. np: Any sys.modules.get(numpy) if np is not None: # avoid infinite recursion on numpy scalars, which have __array__ if np.isscalar(obj): return None elif isinstance(obj, np.ndarray): return obj elif hasattr(obj, __array__) or hasattr(obj, __array_interface__): return np.asarray(obj) return None关键细节通过sys.modules.get(numpy)判断 numpy 是否已加载避免强制引入 numpy 依赖先排除 numpy 标量np.isscalar防止标量自带的__array__方法造成无限递归对np.ndarray直接返回对实现了__array__或__array_interface__的对象如 TensorFlowDeviceArray调用np.asarray(obj)转为 ndarray该函数在 approx.py 的ApproxBase比较流程中被调用expected侧也会经过同样转换因此approx(ndarray)、approx(DeviceScalar(...))等组合均能正常工作。测试用例佐证仓库测试 testing/python/approx.py 中专门保留了针对该回归的回归测试test_numpy_array_protocol其注释直接标注 See issue #8132并在测试中构造了模拟tf.DeviceArray的类class DeviceArray: def __init__(self, value, size): self.value value self.size size def __array__(self): return self.value * np.ones(self.size) expected 1 actual 1 1e-6 assert approx(expected) DeviceArray(actual, size1) assert approx(expected) DeviceArray(actual, size2)同时测试 testing/python/approx.py 的test_numpy_array_implicit_conversion验证了仅实现__array__的“隐式可转换”类型也能正确参与approx比较说明修复对数组协议类对象是通用的而非仅针对单一框架。使用建议approx完整用法可参考其文档字符串approx.py它支持标量、列表、字典、numpy数组等类型默认相对容差rtol1e-5、绝对容差atol1e-8等价于numpy.isclose的默认行为。当被测对象是tf.DeviceArray、torch.Tensor通过__array__等第三方框架的数组时直接与approx比较即可无需手动调用np.asarray转换import pytest def test_device_array(): expected 1.0 actual 1.0 1e-6 # 模拟框架返回的数组类对象 assert approx(expected) actual如何验证当前仓库中的相关代码如果你想在本仓库中亲身体验这两个修复查看异常定义与导入逻辑阅读 pathlib.py重点对比prepend/append与importlib三种模式对sys.path与sys.modules的处理差异查看 approx 修复阅读 approx.py 的_as_numpy_array并运行对应回归测试python -m pytest testing/python/approx.py -k array_protocol or implicit_conversion查看完整变更日志changelog.rst 中保留了 6.2.1 的全部修复记录可作为历史版本行为的权威参考。小结pytest 6.2.1 是一个小而精的 bug-fix 版本approx的数组协议支持让tf.DeviceArray等第三方数组对象重新“可用且可测”Windows UNC 路径下的导入误报修复则提升了企业级共享目录场景下的稳定性。两个修复都体现了 pytest 工程实践中的两个重要原则类型分发要基于对象能力protocol/duck-typing而非继承层级以及路径导入要区分环境差异并保证失败信息可诊断。理解这两个案例也有助于你在编写测试框架或插件时规避同类陷阱。Happy testing.【免费下载链接】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),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →