DEBUG.WIKI
野草云;香港 200Mbps 峰值;不限月流量 · BGP VPS;查看套餐 →
雨云;给项目一台云服务器
晚安云;香港 CN2 ¥15/月

cachetools cachedmethod 让 autospec 报 missing a required argument

cachetools 7.2.2、7.2.3 的 cachedmethod 类访问包装会影响 autospec 调用,7.2.4 已修复。不要给实例补传 self;另行测试真实缓存与调用接口。

升级 cachetools 后,真实对象的方法仍能调用,unittest.mock.create_autospec 生成的对象却在传入一个参数时提示:

TypeError: missing a required argument: 'key'

如果该方法使用 @cachedmethod,并且环境是 cachetools 7.2.2 或 7.2.3,应先核对装饰器描述符与 autospec 的配合。这项回归已在正式 7.2.4 修复,当前版本要求 Python 3.10 及以上。

业务方法只有一个参数,为何 mock 还在等参数

7.2.2 为支持类访问及 super() 调用,调整了 cachedmethod 的描述符。通过类获取方法时会得到带接收者的函数,而 autospec 对这个对象的签名推断没有按正常实例方法去掉接收者,于是已提供的 key 被算到前一个位置。

这不意味着缓存中的 key 丢失,也不要求业务调用者把 self 再传一次。给实例 mock 补一个假的 self,会让测试接口与实际代码分离。

下面是用于核对调用契约的简化示例,缓存行为本身应另用真实对象测试:

from unittest.mock import create_autospec
from cachetools import cachedmethod


class Service:
    def __init__(self):
        self.cache = {}

    @cachedmethod(lambda self: self.cache)
    def cached(self, key):
        return key


service = create_autospec(Service, instance=True)
service.cached.return_value = "value"
result = service.cached("key")
service.cached.assert_called_once_with("key")

7.2.4 的类访问包装对象不再是普通函数,恢复了这一 autospec 调用路径。升级后要重新创建 mock,并在测试使用的解释器里确认依赖已经切换;另一个终端里装了新包,不会改变正在运行的测试进程。

保留其他方法的签名检查

这项修复恢复可调用性,不保证装饰方法在 mock 中拥有与未装饰函数完全相同的严格参数检查。7.2.4 的包装调用采用可变参数,因此不能只凭错误调用不再报错,就断言所有参数都已验证。

若测试必须精确限制服务接口,可以对独立的接口类或协议建立 autospec,把缓存作为具体实现细节;同时用真实 Service 检查缓存命中、不同 key 和失效行为。不要为绕过一个装饰方法的问题,把全套测试都换成不带 spec 的 Mock。

暂时锁定旧依赖需要核对项目为何升级:7.2.2 还包含 super() 等其他修订,整体回退可能恢复另一项已解决的问题。已有 7.2.4 的正式修复时,应优先评估它与项目 Python 及依赖约束的兼容性。

复核时把 mock 调用测试和真实缓存测试分开看:前者检查调用与返回值约定,后者才证明结果确实来自预期缓存。给 mock 设置了 return_value,无法证明真实缓存策略正确。