You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

autospecced Mock无法匹配原函数类型提示的问题排查

问题描述

我希望通过create_autospec生成的autospecced mock能提供与原函数一致的类型提示,但未能实现。以下是测试的最小示例代码:

from __future__ import annotations

import typing
from unittest.mock import create_autospec

import pandas as pd


def func(a: int, c: pd.Timestamp, d: typing.Literal['e', 'f']) -> None:
    pass


func_annotations = func.__annotations__

mock_func = create_autospec(func)


type_hints = typing.get_type_hints(func)
# {'a': <class 'int'>, 'c': <class 'pandas._libs.tslibs.timestamps.Timestamp'>, 'return': <class 'NoneType'>}

# 期望此结果与type_hints一致
type_hints_mocked = typing.get_type_hints(mock_func) # {}

# 尝试复制__annotations__但无效
mock_func.__annotations__ = func_annotations
type_hints_mocked_2 = typing.get_type_hints(mock_func) # NameError: name 'pd' is not defined

请问为何mock函数无法获取与原函数相同的类型提示,以及如何解决该问题?

原因分析
  1. create_autospec生成的Mock对象默认不会继承原函数的__annotations__属性,调用typing.get_type_hints()自然返回空字典。
  2. 因为启用了from __future__ import annotations,函数注解会以字符串形式存储。直接复制原函数的__annotations__给Mock后,get_type_hints()需要解析这些字符串,但Mock对象的__globals__命名空间里没有pd这类导入的名称,解析时就会抛出NameError。
解决方法

方法一:同步Mock的全局命名空间

把原函数的__globals__赋值给Mock对象,让解析字符串注解时能找到所需名称:

from __future__ import annotations

import typing
from unittest.mock import create_autospec

import pandas as pd


def func(a: int, c: pd.Timestamp, d: typing.Literal['e', 'f']) -> None:
    pass


mock_func = create_autospec(func)
# 同步原函数的全局命名空间
mock_func.__globals__ = func.__globals__
# 复制原函数的注解
mock_func.__annotations__ = func.__annotations__

type_hints_mocked = typing.get_type_hints(mock_func)
# 结果与原函数一致:{'a': int, 'c': pandas._libs.tslibs.timestamps.Timestamp, 'return': NoneType}

方法二:直接赋值解析后的类型提示

先通过get_type_hints()拿到原函数解析后的类型,再赋值给Mock的__annotations__,跳过字符串解析步骤:

from __future__ import annotations

import typing
from unittest.mock import create_autospec

import pandas as pd


def func(a: int, c: pd.Timestamp, d: typing.Literal['e', 'f']) -> None:
    pass


mock_func = create_autospec(func)
# 获取原函数解析后的类型提示
resolved_hints = typing.get_type_hints(func)
# 把解析后的类型赋值给Mock的__annotations__
mock_func.__annotations__ = resolved_hints

type_hints_mocked = typing.get_type_hints(mock_func)
# 结果与原函数一致

方法三:结合functools.wraps包装Mock

用functools.wraps把原函数的元数据(包括注解)复制给Mock,同时保留create_autospec生成的mock行为:

from __future__ import annotations
import functools
import typing
from unittest.mock import create_autospec

import pandas as pd


def func(a: int, c: pd.Timestamp, d: typing.Literal['e', 'f']) -> None:
    pass


mock_func = create_autospec(func)
# 使用wraps复制原函数的元数据
mock_func = functools.wraps(func)(mock_func)

type_hints_mocked = typing.get_type_hints(mock_func)
# 结果与原函数一致

内容的提问来源于stack exchange,提问作者ano

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 15:35:29