Flask源码:app.py (一)装饰器函数和run()函数

@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
发布了23 篇原创文章 · 获赞 0 · 访问量 2014

猜你喜欢

转载自blog.csdn.net/qq_33913982/article/details/104243074
今日推荐