背景:
这两天在看后端代码覆盖率平台代码的时候,发现启动服务只需要执行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实例并返回,如果没有,则报错。文章来源:https://www.toymoban.com/news/detail-588103.html
至此,终于知道Flask app对象是怎么创建,在哪里创建的了。文章来源地址https://www.toymoban.com/news/detail-588103.html
到了这里,关于Flask入门:flask run运行入口函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!