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 中的入口函数:

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()函数

    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文件的内容可以如下:

FLASK_APP=coverage_statistics

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

3、接着调用super.main()

...中间省略很多步

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

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对象是怎么创建,在哪里创建的了。

你可能感兴趣的:(python,#,flask,flask,python,后端)