Mypy + FastAPI response_model

oyb*_*lix 5 python typing mypy fastapi

我的任务是在我们的 FastAPI 项目中处理从 Mypy 0.770 到 0.870 的更新,这产生了一个我无法完全理解的错误。我的端点可以根据某些条件返回两个不同的模型,这在 endpont 装饰器中表示如下:

@router.get("/", response_model=Union[Model1, Model2])
Run Code Online (Sandbox Code Playgroud)

Mypy 0.870 现在抱怨这个,指出

Argument "response_model" to "get" of "APIRouter" has incompatible type "object"; expected "Optional[Type[Any]]"
Run Code Online (Sandbox Code Playgroud)

将其设置为单一类型,例如Model1甚至str消除错误。Any然而,这并不能正常工作。

现在,查看该get方法,我看到response_model参数的类型为Type[Any],我认为它必须是一个指针。

如何为我的 API 定义非简单的返回模型,并使 Mypy 开心?

编辑:我试图在较小的框架中重现该问题,但不能。以下代码工作正常:

from typing import Any, Type, Union


def test1(var, response_model: Type[Any]):
    print(f"Accepted Type[Any], {var}")

def test2(var, response_model: Union[dict, set]):
    print(f"Accepted Union, {var}")

def main():
    test1('test1', response_model=Union[dict, set])
    test2('test2', response_model=Union[dict, set])

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

via*_*ixt 4

这是较新版本的 mypy 中引入的兼容性问题。Github 上有一个关于此主题的未决问题: https://github.com/tiangolo/fastapi/issues/2279

在讨论中,他们提供了以下解决方法:

  • 使用不同的方法创建类型别名:

    NewModel = TypeVar('NewModel',Model1,Model2)

  • 创建一个新的 Pydantic 模型:

    class NewModel(BaseModel):
         __root__: Union[Model1, Model2]
    
    Run Code Online (Sandbox Code Playgroud)