Python 对导入的 Flask 模块进行类型提示

Python type hinting on imported Flask modules

我发现 Flask 的自动完成功能有些欠缺。这是因为在内部,特定于上下文的对象(例如 current_apprequestlogger 实际上是 LocalProxy 对象。因此 PyCharm 合理地不知道如何处理这种类型。

一种解决方案是对导入的模块应用类型提示。除了你不能那样做!从 Python 3.7 开始,似乎没有这样的语法来促进这一点。

因此,下一个显而易见的解决方案是制作每个上下文特定模块的本地副本,并明确设置类型,如下所示:

from logging import Logger
from flask import Flask, Request, Blueprint, request, current_app as app
    
app: Flask = app
logger: Logger = app.logger
request: Request = request

这一直有效,直到您实际尝试启动服务器,在这种情况下,应用程序会因为 RuntimeError: Working outside of application context.

而崩溃

事实证明,我们实际上可以将相关类型提示封装在应用程序上下文中的 class 或其他范围内。

@foo_blueprint.route('/foo', methods=['GET'])
def foo(cls):
    _app: Flask = app
    _logger: Logger = app.logger
    _request: Request = request
    # ...

这可行,但在任何可以想象的意义上都非常笨拙。

在 Flask 的应用程序上下文中获取正确的类型提示是否有合理的解决方案?

你试过了吗?我知道它至少在从其他模块导入普通变量时有效。

# in module_a.py
my_str = 23


# in module_b.py
from module_a import my_str

my_str: str

# The IDE should now suggest string methods when trying to access
# properties of `my_str`

2022 年更新

开始于 Flask version 2.0.0, type hints are now built-in to the library. (See pull request #3973)

2.0.0 之前的 Flask 版本

对于旧版本的 Flask,一种解决方法是使用类型转换,如下所示:

from typing import cast

from flask import request
from flask import Request
from flask import Response


@app.route('/')
def index() -> Response:
    # Can't use `assert isinstance(request, Request)`, since `request` is `LocalProxy` object.
    global request
    request = cast(Request, request)

    token = request.headers.get('authorization')
    ... 
    return 'API is working', 200