@app.route('/')视图函数路由装饰器
def route(self, rule, **options):
"""
add_url_rule类方法的封装,可以自定义参数,但第一次参数是rule
"""
def decorator(f):
endpoint = options.pop("endpoint", None)
#把被装饰函数和rule等参数传入add_url_rule了
self.add_url_rule(rule, endpoint, f, **options)
return f
return decorator
@setupmethod #调试用的装饰器
def add_url_rule(
self,
rule,
endpoint=None,
view_func=None,
provide_automatic_options=None,
**options
):
if endpoint is None:
"""
def _endpoint_from_view_func(view_func):
assert view_func is not None, "expected view func if endpoint is not provided."
return view_func.__name__
"""
#直接返回view_func.__name__
endpoint = _endpoint_from_view_func(view_func)
options["endpoint"] = endpoint
#获取用户接受的方法list,比如@app.route('/',methods=['GET','POST'])
methods = options.pop("methods", None)
if methods is None:#获取默认方法
methods = getattr(view_func, "methods", None) or ("GET",)
if isinstance(methods, string_types):#methods不能是string类型
raise TypeError(
"Allowed methods have to be iterables of strings, "
'for example: @app.route(..., methods=["POST"])'
)
methods = set(item.upper() for item in methods)# methods大写化并去重
# Methods that should always be added#自定义的required_methods属性
required_methods = set(getattr(view_func, "required_methods", ()))
# starting with Flask 0.8 the view_func object can disable and
# force-enable the automatic options handling.#自定义provide_automatic_options
# 设置view_func 是否是原子操作
if provide_automatic_options is None:
provide_automatic_options = getattr(
view_func, "provide_automatic_options", None
)
if provide_automatic_options is None:
if "OPTIONS" not in methods:
provide_automatic_options = True
required_methods.add("OPTIONS")
else:
provide_automatic_options = False
methods |= required_methods
"""
from werkzeug.routing import Rule
''
''
class Flask(_PackageBoundObject):
''
''
#: The rule object to use for URL rules created. This is used by
#: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`.
url_rule_class = Rule
''
''
#: A dictionary of all view functions registered. The keys will
#: be function names which are also used to generate URLs and
#: the values are the function objects themselves.
#: To register a view function, use the :meth:`route` decorator.
self.view_functions = {}
"""
# 这里调用werkzeug的Rule类方法了
rule = self.url_rule_class(rule, methods=methods, **options)
rule.provide_automatic_options = provide_automatic_options
#绑定view_func,一个字典保存endpoint(默认是view_func.__name__)和view_func
self.url_map.add(rule)
if view_func is not None:
old_func = self.view_functions.get(endpoint)
if old_func is not None and old_func != view_func:
raise AssertionError(
"View function mapping is overwriting an "
"existing endpoint function: %s" % endpoint
)
self.view_functions[endpoint] = view_func
@setupmethod
def endpoint(self, endpoint):
"""A decorator to register a function as an endpoint.
Example::
@app.endpoint('example.endpoint')
def example():
return "example"
:param endpoint: the name of the endpoint
"""
def decorator(f):
self.view_functions[endpoint] = f
return f
return decorator
def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
from .debughelpers import explain_ignored_app_run
explain_ignored_app_run()
return
if get_load_dotenv(load_dotenv):
cli.load_dotenv()
# if set, let env vars override previous values
if "FLASK_ENV" in os.environ:
self.env = get_env()
self.debug = get_debug_flag()
elif "FLASK_DEBUG" in os.environ:
self.debug = get_debug_flag()
#设置debug
if debug is not None:
self.debug = bool(debug)
#几种设置host和port的途径
_host = "127.0.0.1" #默认host
_port = 5000 #默认port
server_name = self.config.get("SERVER_NAME")
sn_host, sn_port = None, None
if server_name:
sn_host, _, sn_port = server_name.partition(":")
host = host or sn_host or _host
# pick the first value that's not None (0 is allowed)
port = int(next((p for p in (port, sn_port) if p is not None), _port))
"""
@property
def debug(self):#封装config["DEBUG"]的获取
return self.config["DEBUG"]
@debug.setter
def debug(self, value):#封装config["DEBUG"]的设置
self.config["DEBUG"] = value
self.jinja_env.auto_reload = self.templates_auto_reload
"""
#设置默认的run_simple的参数,如代码修改重启,使用调试器,为每个请求创建线程与否
options.setdefault("use_reloader", self.debug)
options.setdefault("use_debugger", self.debug)
options.setdefault("threaded", True)
"""
运行run控制台输出的提示
* Serving Flask app "app.py"
* Environment: development
* Debug mode: off
函数在cli.py文件中,使用click.echo()代替print,可达到兼容python 2/3
"""
cli.show_server_banner(self.env, self.debug, self.name, False)
#转入werkzeug.serving.run_simple
from werkzeug.serving import run_simple
try:
run_simple(host, port, self, **options)
finally:
self._got_first_request = False