Flask入门:flask run运行入口函数

背景:

这两天在看后端代码覆盖率平台代码的时候,发现启动服务只需要执行flask run命令即可。但是找了半天都没有看到工程中Flask app实例对象是在哪里创建的。工程中定义了一个create_app()函数,可是没有看到调用它的地方。带着疑惑,尝试在工程中create_app()函数主动raise一个异常,来看看flask run从入口函数是怎么运行到create_app(),是如何调用create_app()函数的。

1、在命令行中执行flask启动命令flask run,其内部执行的是工程名\venv\Lib\site-packages\flask\cli.py 中的入口函数:

python 复制代码
def main() -> None:
    if int(click.__version__[0]) < 8:
        warnings.warn(
            "Using the `flask` cli with Click 7 is deprecated and"
            " will not be supported starting with Flask 2.1."
            " Please upgrade to Click 8 as soon as possible.",
            DeprecationWarning,
        )
    # TODO omit sys.argv once https://github.com/pallets/click/issues/536 is fixed
    cli.main(args=sys.argv[1:])


if __name__ == "__main__":
    main()

可以看到,主要的逻辑是在cli.main()函数中。

2、cli.main()函数

python 复制代码
    def main(self, *args, **kwargs):
        # Set a global flag that indicates that we were invoked from the
        # command line interface. This is detected by Flask.run to make the
        # call into a no-op. This is necessary to avoid ugly errors when the
        # script that is loaded here also attempts to start a server.
        os.environ["FLASK_RUN_FROM_CLI"] = "true"

        if get_load_dotenv(self.load_dotenv):
            load_dotenv()

        obj = kwargs.get("obj")

        if obj is None:
            obj = ScriptInfo(
                create_app=self.create_app, set_debug_flag=self.set_debug_flag
            )

        kwargs["obj"] = obj
        kwargs.setdefault("auto_envvar_prefix", "FLASK")
        return super().main(*args, **kwargs)

其中在load_dotenv()函数中加载工程下的".env"或".flaskenv"文件进行设置环境变量。.flaskenv文件的内容可以如下:

bash 复制代码
FLASK_APP=coverage_statistics

# 默认环境变量设置为development
FLASK_ENV=development
# FLASK_ENV=production
# FLASK_DEBUG = True

3、接着调用super.main()

...中间省略很多步

n、调用find_best_app() 该函数根据给定的模块名称,尝试在该模块中找到一个最有可能的应用,没有找到就会报错。

python 复制代码
def find_best_app(script_info, module):
    """Given a module instance this tries to find the best possible
    application in the module or raises an exception.
    """
    from . import Flask

    # Search for the most common names first.
    for attr_name in ("app", "application"):
        app = getattr(module, attr_name, None)

        if isinstance(app, Flask):
            return app

    # Otherwise find the only object that is a Flask instance.
    matches = [v for v in module.__dict__.values() if isinstance(v, Flask)]

    if len(matches) == 1:
        return matches[0]
    elif len(matches) > 1:
        raise NoAppException(
            "Detected multiple Flask applications in module"
            f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
            f" to specify the correct one."
        )

    # Search for app factory functions.
    for attr_name in ("create_app", "make_app"):
        app_factory = getattr(module, attr_name, None)

        if inspect.isfunction(app_factory):
            try:
                app = call_factory(script_info, app_factory)

                if isinstance(app, Flask):
                    return app
            except TypeError as e:
                if not _called_with_wrong_args(app_factory):
                    raise

                raise NoAppException(
                    f"Detected factory {attr_name!r} in module {module.__name__!r},"
                    " but could not call it without arguments. Use"
                    f" \"FLASK_APP='{module.__name__}:{attr_name}(args)'\""
                    " to specify arguments."
                ) from e

    raise NoAppException(
        "Failed to find Flask application or factory in module"
        f" {module.__name__!r}. Use 'FLASK_APP={module.__name__}:name'"
        " to specify one."
    )

1、先尝试在模块中查找是否有app或application名称的文件,没有则进入第二步;

2、然后查找模块中是否有Flask实例的属性对象,有一个则表明找到了,有多个则报错,没有则进入第三步;

3、查找是否有app工程方法"create_app"或"make_app",如果存在,则调用该工程方法创建app实例并返回,如果没有,则报错。

至此,终于知道Flask app对象是怎么创建,在哪里创建的了。

相关推荐
qq_297574671 天前
【实战教程】SpringBoot 实现多文件批量下载并打包为 ZIP 压缩包
java·spring boot·后端
好家伙VCC1 天前
### WebRTC技术:实时通信的革新与实现####webRTC(Web Real-TimeComm
java·前端·python·webrtc
前端玖耀里1 天前
如何使用python的boto库和SES发送电子邮件?
python
serve the people1 天前
python环境搭建 (十二) pydantic和pydantic-settings类型验证与解析
java·网络·python
小天源1 天前
Error 1053 Error 1067 服务“启动后立即停止” Java / Python 程序无法后台运行 windows nssm注册器下载与报错处理
开发语言·windows·python·nssm·error 1053·error 1067
喵手1 天前
Python爬虫实战:HTTP缓存系统深度实战 — ETag、Last-Modified与requests-cache完全指南(附SQLite持久化存储)!
爬虫·python·爬虫实战·http缓存·etag·零基础python爬虫教学·requests-cache
喵手1 天前
Python爬虫实战:容器化与定时调度实战 - Docker + Cron + 日志轮转 + 失败重试完整方案(附CSV导出 + SQLite持久化存储)!
爬虫·python·爬虫实战·容器化·零基础python爬虫教学·csv导出·定时调度
2601_949146531 天前
Python语音通知接口接入教程:开发者快速集成AI语音API的脚本实现
人工智能·python·语音识别
寻梦csdn1 天前
pycharm+miniconda兼容问题
ide·python·pycharm·conda
Java面试题总结1 天前
基于 Java 的 PDF 文本水印实现方案(iText7 示例)
java·python·pdf