Getting started with Flask: flask run runs the entry function

background:

When looking at the back-end code coverage platform code in the past two days, I found that starting the service only needs to execute the flask run command. But after looking for a long time, I didn't see where the Flask app instance object in the project was created. A create_app() function is defined in the project, but there is no place to call it. With doubts, try to actively raise an exception in the create_app() function in the project, to see how the flask run runs from the entry function to create_app(), and how to call the create_app() function.

 1. Execute the flask startup command flask run on the command line, which executes the entry function in the project name\venv\Lib\site-packages\flask\cli.py inside:

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

        As you can see, the main logic is in the cli.main() function.

2. cli.main() function

    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)

        Among them, the ".env" or ".flaskenv" file under the project is loaded in the load_dotenv() function to set the environment variable. The contents of the .flaskenv file can be as follows:

FLASK_APP=coverage_statistics

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

3. Then call super.main()

...omit a lot of steps in between

n. Call find_best_app() This function tries to find the most likely application in the module according to the given module name, if not found, an error will be reported.

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. First try to find whether there is a file named app or application in the module, if not, enter the second step;

        2. Then check whether there is an attribute object of the Flask instance in the module. If there is one, it means that it is found. If there are more than one, an error will be reported. If there is no one, go to the third step;

        3. Find out whether there is an app engineering method "create_app" or "make_app". If it exists, call the engineering method to create an app instance and return it. If not, report an error.

        So far, I finally know how and where the Flask app object is created.

Guess you like

Origin blog.csdn.net/liuqinhou/article/details/131780338