flask源码笔记:三,app.py模块(7)——Flask的方法(下)

源代码:
    @setupmethod
    def before_request(self, f):
        """Registers a function to run before each request."""
        self.before_request_funcs.setdefault(None, []).append(f)
        return f
#定义每个请求前执行的函数的装饰器


    @setupmethod
    def before_first_request(self, f):
        """Registers a function to be run before the first request to this
        instance of the application.


        .. versionadded:: 0.8
        """
        self.before_first_request_funcs.append(f)
#定义第一个请求前执行的函数的装饰器


    @setupmethod
    def after_request(self, f):
        """Register a function to be run after each request.  Your function
        must take one parameter, a :attr:`response_class` object and return
        a new response object or the same (see :meth:`process_response`).


        As of Flask 0.7 this function might not be executed at the end of the
        request in case an unhandled exception occurred.
        """
        self.after_request_funcs.setdefault(None, []).append(f)
        return f
#定义每次请求后响应前执行的函数的装饰器


    @setupmethod
    def teardown_request(self, f):
        """Register a function to be run at the end of each request,
        regardless of whether there was an exception or not.  These functions
        are executed when the request context is popped, even if not an
        actual request was performed.


        Example::


            ctx = app.test_request_context()
            ctx.push()
            ...
            ctx.pop()


        When ``ctx.pop()`` is executed in the above example, the teardown
        functions are called just before the request context moves from the
        stack of active contexts.  This becomes relevant if you are using
        such constructs in tests.


        Generally teardown functions must take every necessary step to avoid
        that they will fail.  If they do execute code that might fail they
        will have to surround the execution of these code by try/except
        statements and log occurring errors.


        When a teardown function was called because of a exception it will
        be passed an error object.


        .. admonition:: Debug Note


           In debug mode Flask will not tear down a request on an exception
           immediately.  Instead if will keep it alive so that the interactive
           debugger can still access it.  This behavior can be controlled
           by the ``PRESERVE_CONTEXT_ON_EXCEPTION`` configuration variable.
        """
        self.teardown_request_funcs.setdefault(None, []).append(f)
        return f
#这个装饰器下 的函 #数在响应对象构建后被调用。它们不允许修改请求,并且它们的返回值被忽略。如果  #请求过程中出错,那么这个错误会传递给每个函数;否则传递 None 。


    @setupmethod
    def teardown_appcontext(self, f):
        """Registers a function to be called when the application context
        ends.  These functions are typically also called when the request
        context is popped.


        Example::


            ctx = app.app_context()
            ctx.push()
            ...
            ctx.pop()


        When ``ctx.pop()`` is executed in the above example, the teardown
        functions are called just before the app context moves from the
        stack of active contexts.  This becomes relevant if you are using
        such constructs in tests.


        Since a request context typically also manages an application
        context it would also be called when you pop a request context.


        When a teardown function was called because of an exception it will
        be passed an error object.


        .. versionadded:: 0.9
        """
        self.teardown_appcontext_funcs.append(f)
        return f
#定义当应用程序上下文出现丢失等问题时,应该执行的函数的装饰器


    @setupmethod
    def context_processor(self, f):
        """Registers a template context processor function."""
        self.template_context_processors[None].append(f)
        return f
#装饰器,将定义的函数传入到模板环境中


    @setupmethod
    def url_value_preprocessor(self, f):
        """Registers a function as URL value preprocessor for all view
        functions of the application.  It's called before the view functions
        are called and can modify the url values provided.
        """
        self.url_value_preprocessors.setdefault(None, []).append(f)
        return f
#保存一系列函数,他们在请求成功匹配并且能够执行针对 URL 值的代码时立即执行。实际上,他们将信息从包含这些值的字 #典当中取出,然后将其放在某个其他的地方:
#@app.url_value_preprocessor
#def pull_lang_code(endpoint, values):
#    g.lang_code = values.pop('lang_code', None)




    @setupmethod
    def url_defaults(self, f):
        """Callback function for URL defaults for all view functions of the
        application.  It's called with the endpoint and values and should
        update the values passed in place.
        """
        self.url_default_functions.setdefault(None, []).append(f)
        return f
#保存一系列函数,他们在使用url_for函数是自动调用
#@app.url_defaults
#def add_language_code(endpoint, values):
#    if 'lang_code' in values or not g.lang_code:
#        return
#    if app.url_map.is_endpoint_expecting(endpoint, 'lang_code'):
#        values['lang_code'] = g.lang_code


#@app.url_value_preprocessor和@app.url_defaults配合使用,可以一次处理url规则,从而对所有url生  #效。例如需要检查url中的语言规则的例子。先用@app.url_value_preprocessor获取并剔除该参数 #lang_code,然后在@app.url_defaults中将其插入到参数列表中。




    def handle_http_exception(self, e):
        """Handles an HTTP exception.  By default this will invoke the
        registered error handlers and fall back to returning the
        exception as response.


        .. versionadded:: 0.3
        """
        handlers = self.error_handler_spec.get(request.blueprint)
        # Proxy exceptions don't have error codes.  We want to always return
        # those unchanged as errors
        if e.code is None:
            return e
        if handlers and e.code in handlers:
            handler = handlers[e.code]
        else:
            handler = self.error_handler_spec[None].get(e.code)
        if handler is None:
            return e
        return handler(e)
#http异常处理函数


    def trap_http_exception(self, e):
        """Checks if an HTTP exception should be trapped or not.  By default
        this will return `False` for all exceptions except for a bad request
        key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to `True`.  It
        also returns `True` if ``TRAP_HTTP_EXCEPTIONS`` is set to `True`.


        This is called for all HTTP exceptions raised by a view function.
        If it returns `True` for any exception the error handler for this
        exception is not called and it shows up as regular exception in the
        traceback.  This is helpful for debugging implicitly raised HTTP
        exceptions.


        .. versionadded:: 0.8
        """
        if self.config['TRAP_HTTP_EXCEPTIONS']:
            return True
        if self.config['TRAP_BAD_REQUEST_ERRORS']:
            return isinstance(e, BadRequest)
        return False
#校验是否对http异常进行抓取


    def handle_user_exception(self, e):
        """This method is called whenever an exception occurs that should be
        handled.  A special case are
        :class:`~werkzeug.exception.HTTPException`\s which are forwarded by
        this function to the :meth:`handle_http_exception` method.  This
        function will either return a response value or reraise the
        exception with the same traceback.


        .. versionadded:: 0.7
        """
        exc_type, exc_value, tb = sys.exc_info()
        assert exc_value is e


        # ensure not to trash sys.exc_info() at that point in case someone
        # wants the traceback preserved in handle_http_exception.  Of course
        # we cannot prevent users from trashing it themselves in a custom
        # trap_http_exception method so that's their fault then.
        if isinstance(e, HTTPException) and not self.trap_http_exception(e):
            return self.handle_http_exception(e)


        blueprint_handlers = ()
        handlers = self.error_handler_spec.get(request.blueprint)
        if handlers is not None:
            blueprint_handlers = handlers.get(None, ())
        app_handlers = self.error_handler_spec[None].get(None, ())
        for typecheck, handler in chain(blueprint_handlers, app_handlers):
            if isinstance(e, typecheck):
                return handler(e)


        reraise(exc_type, exc_value, tb)
#处理用户错误的函数


    def handle_exception(self, e):
        """Default exception handling that kicks in when an exception
        occurs that is not caught.  In debug mode the exception will
        be re-raised immediately, otherwise it is logged and the handler
        for a 500 internal server error is used.  If no such handler
        exists, a default 500 internal server error message is displayed.


        .. versionadded:: 0.3
        """
        exc_type, exc_value, tb = sys.exc_info()


        got_request_exception.send(self, exception=e)
        handler = self.error_handler_spec[None].get(500)


        if self.propagate_exceptions:
            # if we want to repropagate the exception, we can attempt to
            # raise it with the whole traceback in case we can do that
            # (the function was actually called from the except part)
            # otherwise, we just raise the error again
            if exc_value is e:
                reraise(exc_type, exc_value, tb)
            else:
                raise e


        self.log_exception((exc_type, exc_value, tb))
        if handler is None:
            return InternalServerError()
        return handler(e)
#处理服务器错误的函数


    def log_exception(self, exc_info):
        """Logs an exception.  This is called by :meth:`handle_exception`
        if debugging is disabled and right before the handler is called.
        The default implementation logs the exception as error on the
        :attr:`logger`.


        .. versionadded:: 0.8
        """
        self.logger.error('Exception on %s [%s]' % (
            request.path,
            request.method
        ), exc_info=exc_info)
#对异常添加日志记录


    def raise_routing_exception(self, request):
        """Exceptions that are recording during routing are reraised with
        this method.  During debug we are not reraising redirect requests
        for non ``GET``, ``HEAD``, or ``OPTIONS`` requests and we're raising
        a different error instead to help debug situations.


        :internal:
        """
        if not self.debug \
           or not isinstance(request.routing_exception, RequestRedirect) \
           or request.method in ('GET', 'HEAD', 'OPTIONS'):
            raise request.routing_exception


        from .debughelpers import FormDataRoutingRedirect
        raise FormDataRoutingRedirect(request)
#引发路由异常的函数


    def dispatch_request(self):
        """Does the request dispatching.  Matches the URL and returns the
        return value of the view or error handler.  This does not have to
        be a response object.  In order to convert the return value to a
        proper response object, call :func:`make_response`.


        .. versionchanged:: 0.7
           This no longer does the exception handling, this code was
           moved to the new :meth:`full_dispatch_request`.
        """
        req = _request_ctx_stack.top.request
        if req.routing_exception is not None:
            self.raise_routing_exception(req)
        rule = req.url_rule
        # if we provide automatic options for this URL and the
        # request came with the OPTIONS method, reply automatically
        if getattr(rule, 'provide_automatic_options', False) \
           and req.method == 'OPTIONS':
            return self.make_default_options_response()
        # otherwise dispatch to the handler for that endpoint
        return self.view_functions[rule.endpoint](**req.view_args)
#获取请求之后,进行调度的函数,核心函数之一


    def full_dispatch_request(self):
        """Dispatches the request and on top of that performs request
        pre and postprocessing as well as HTTP exception catching and
        error handling.


        .. versionadded:: 0.7
        """
        self.try_trigger_before_first_request_functions()
        try:
            request_started.send(self)
            rv = self.preprocess_request()
            if rv is None:
                rv = self.dispatch_request()
        except Exception as e:
            rv = self.handle_user_exception(e)
        response = self.make_response(rv)
        response = self.process_response(response)
        request_finished.send(self, response=response)
        return response
#整个请求的完整调度过程函数,核心函数之一


    def try_trigger_before_first_request_functions(self):
        """Called before each request and will ensure that it triggers
        the :attr:`before_first_request_funcs` and only exactly once per
        application instance (which means process usually).


        :internal:
        """
        if self._got_first_request:
            return
        with self._before_request_lock:
            if self._got_first_request:
                return
            self._got_first_request = True
            for func in self.before_first_request_funcs:
                func()
#触发第一个请求时的执行的函数(包含执行诸多的定义的第一个请求之前需要执行的函数)


    def make_default_options_response(self):
        """This method is called to create the default `OPTIONS` response.
        This can be changed through subclassing to change the default
        behavior of `OPTIONS` responses.


        .. versionadded:: 0.7
        """
        adapter = _request_ctx_stack.top.url_adapter
        if hasattr(adapter, 'allowed_methods'):
            methods = adapter.allowed_methods()
        else:
            # fallback for Werkzeug < 0.7
            methods = []
            try:
                adapter.match(method='--')
            except MethodNotAllowed as e:
                methods = e.valid_methods
            except HTTPException as e:
                pass
        rv = self.response_class()
        rv.allow.update(methods)
        return rv
#创建默认的option方法的响应的函数


    def should_ignore_error(self, error):
        """This is called to figure out if an error should be ignored
        or not as far as the teardown system is concerned.  If this
        function returns `True` then the teardown handlers will not be
        passed the error.


        .. versionadded:: 0.10
        """
        return False
#类似一个只读的属性,只返回False,不能忽略错误


    def make_response(self, rv):
        """Converts the return value from a view function to a real
        response object that is an instance of :attr:`response_class`.


        The following types are allowed for `rv`:


        .. tabularcolumns:: |p{3.5cm}|p{9.5cm}|


        ======================= ===========================================
        :attr:`response_class`  the object is returned unchanged
        :class:`str`            a response object is created with the
                                string as body
        :class:`unicode`        a response object is created with the
                                string encoded to utf-8 as body
        a WSGI function         the function is called as WSGI application
                                and buffered as response object
        :class:`tuple`          A tuple in the form ``(response, status,
                                headers)`` where `response` is any of the
                                types defined here, `status` is a string
                                or an integer and `headers` is a list of
                                a dictionary with header values.
        ======================= ===========================================


        :param rv: the return value from the view function


        .. versionchanged:: 0.9
           Previously a tuple was interpreted as the arguments for the
           response object.
        """
        status = headers = None
        if isinstance(rv, tuple):
            rv, status, headers = rv + (None,) * (3 - len(rv))


        if rv is None:
            raise ValueError('View function did not return a response')


        if not isinstance(rv, self.response_class):
            # When we create a response object directly, we let the constructor
            # set the headers and status.  We do this because there can be
            # some extra logic involved when creating these objects with
            # specific values (like default content type selection).
            if isinstance(rv, (text_type, bytes, bytearray)):
                rv = self.response_class(rv, headers=headers, status=status)
                headers = status = None
            else:
                rv = self.response_class.force_type(rv, request.environ)


        if status is not None:
            if isinstance(status, string_types):
                rv.status = status
            else:
                rv.status_code = status
        if headers:
            rv.headers.extend(headers)


        return rv
#制作响应的函数,核心函数之一


    def create_url_adapter(self, request):
        """Creates a URL adapter for the given request.  The URL adapter
        is created at a point where the request context is not yet set up
        so the request is passed explicitly.


        .. versionadded:: 0.6


        .. versionchanged:: 0.9
           This can now also be called without a request object when the
           URL adapter is created for the application context.
        """
        if request is not None:
            return self.url_map.bind_to_environ(request.environ,
                server_name=self.config['SERVER_NAME'])
        # We need at the very least the server name to be set for this
        # to work.
        if self.config['SERVER_NAME'] is not None:
            return self.url_map.bind(
                self.config['SERVER_NAME'],
                script_name=self.config['APPLICATION_ROOT'] or '/',
                url_scheme=self.config['PREFERRED_URL_SCHEME'])
#创建以配置参数SERVER_NAME为key,其后值为value的域名为访问应用(根)域名的唯一方法


    def inject_url_defaults(self, endpoint, values):
        """Injects the URL defaults for the given endpoint directly into
        the values dictionary passed.  This is used internally and
        automatically called on URL building.


        .. versionadded:: 0.7
        """
        funcs = self.url_default_functions.get(None, ())
        if '.' in endpoint:
            bp = endpoint.rsplit('.', 1)[0]
            funcs = chain(funcs, self.url_default_functions.get(bp, ()))
        for func in funcs:
            func(endpoint, values)
#注入已定义的url_defaults装饰器下的函数


    def handle_url_build_error(self, error, endpoint, values):
        """Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`.
        """
        exc_type, exc_value, tb = sys.exc_info()
        for handler in self.url_build_error_handlers:
            try:
                rv = handler(error, endpoint, values)
                if rv is not None:
                    return rv
            except BuildError as error:
                pass


        # At this point we want to reraise the exception.  If the error is
        # still the same one we can reraise it with the original traceback,
        # otherwise we raise it from here.
        if error is exc_value:
            reraise(exc_type, exc_value, tb)
        raise error
#处理url build错误


    def preprocess_request(self):
        """Called before the actual request dispatching and will
        call every as :meth:`before_request` decorated function.
        If any of these function returns a value it's handled as
        if it was the return value from the view and further
        request handling is stopped.


        This also triggers the :meth:`url_value_processor` functions before
        the actual :meth:`before_request` functions are called.
        """
        bp = _request_ctx_stack.top.request.blueprint


        funcs = self.url_value_preprocessors.get(None, ())
        if bp is not None and bp in self.url_value_preprocessors:
            funcs = chain(funcs, self.url_value_preprocessors[bp])
        for func in funcs:
            func(request.endpoint, request.view_args)


        funcs = self.before_request_funcs.get(None, ())
        if bp is not None and bp in self.before_request_funcs:
            funcs = chain(funcs, self.before_request_funcs[bp])
        for func in funcs:
            rv = func()
            if rv is not None:
                return rv
#预处理请求的函数,核心函数之一,先处理@app.url_value_preprocessor装饰器的函数,
#再处理@app.before_request装饰器的函数


    def process_response(self, response):
        """Can be overridden in order to modify the response object
        before it's sent to the WSGI server.  By default this will
        call all the :meth:`after_request` decorated functions.


        .. versionchanged:: 0.5
           As of Flask 0.5 the functions registered for after request
           execution are called in reverse order of registration.


        :param response: a :attr:`response_class` object.
        :return: a new response object or the same, has to be an
                 instance of :attr:`response_class`.
        """
        ctx = _request_ctx_stack.top
        bp = ctx.request.blueprint
        funcs = ctx._after_request_functions
        if bp is not None and bp in self.after_request_funcs:
            funcs = chain(funcs, reversed(self.after_request_funcs[bp]))
        if None in self.after_request_funcs:
            funcs = chain(funcs, reversed(self.after_request_funcs[None]))
        for handler in funcs:
            response = handler(response)
        if not self.session_interface.is_null_session(ctx.session):
            self.save_session(ctx.session, response)
        return response
#处理响应,核心函数之一,处理@app.after_request装饰器的函数


    def do_teardown_request(self, exc=None):
        """Called after the actual request dispatching and will
        call every as :meth:`teardown_request` decorated function.  This is
        not actually called by the :class:`Flask` object itself but is always
        triggered when the request context is popped.  That way we have a
        tighter control over certain resources under testing environments.


        .. versionchanged:: 0.9
           Added the `exc` argument.  Previously this was always using the
           current exception information.
        """
        if exc is None:
            exc = sys.exc_info()[1]
        funcs = reversed(self.teardown_request_funcs.get(None, ()))
        bp = _request_ctx_stack.top.request.blueprint
        if bp is not None and bp in self.teardown_request_funcs:
            funcs = chain(funcs, reversed(self.teardown_request_funcs[bp]))
        for func in funcs:
            rv = func(exc)
        request_tearing_down.send(self, exc=exc)
#执行app.teardown_request_funcs字典中的函数


    def do_teardown_appcontext(self, exc=None):
        """Called when an application context is popped.  This works pretty
        much the same as :meth:`do_teardown_request` but for the application
        context.


        .. versionadded:: 0.9
        """
        if exc is None:
            exc = sys.exc_info()[1]
        for func in reversed(self.teardown_appcontext_funcs):
            func(exc)
        appcontext_tearing_down.send(self, exc=exc)
#执行app.teardown_appcontext_funcs字典中的函数


    def app_context(self):
        """Binds the application only.  For as long as the application is bound
        to the current context the :data:`flask.current_app` points to that
        application.  An application context is automatically created when a
        request context is pushed if necessary.


        Example usage::


            with app.app_context():
                ...


        .. versionadded:: 0.9
        """
        return AppContext(self)
#返回应用程序上下文


    def request_context(self, environ):
        """Creates a :class:`~flask.ctx.RequestContext` from the given
        environment and binds it to the current context.  This must be used in
        combination with the `with` statement because the request is only bound
        to the current context for the duration of the `with` block.


        Example usage::


            with app.request_context(environ):
                do_something_with(request)


        The object returned can also be used without the `with` statement
        which is useful for working in the shell.  The example above is
        doing exactly the same as this code::


            ctx = app.request_context(environ)
            ctx.push()
            try:
                do_something_with(request)
            finally:
                ctx.pop()


        .. versionchanged:: 0.3
           Added support for non-with statement usage and `with` statement
           is now passed the ctx object.


        :param environ: a WSGI environment
        """
        return RequestContext(self, environ)
#返回请求上下文


    def test_request_context(self, *args, **kwargs):
        """Creates a WSGI environment from the given values (see
        :func:`werkzeug.test.EnvironBuilder` for more information, this
        function accepts the same arguments).
        """
        from flask.testing import make_test_environ_builder
        builder = make_test_environ_builder(self, *args, **kwargs)
        try:
            return self.request_context(builder.get_environ())
        finally:
            builder.close()
#尝试返回测试请求的上下文


    def wsgi_app(self, environ, start_response):
        """The actual WSGI application.  This is not implemented in
        `__call__` so that middlewares can be applied without losing a
        reference to the class.  So instead of doing this::


            app = MyMiddleware(app)


        It's a better idea to do this instead::


            app.wsgi_app = MyMiddleware(app.wsgi_app)


        Then you still have the original application object around and
        can continue to call methods on it.


        .. versionchanged:: 0.7
           The behavior of the before and after request callbacks was changed
           under error conditions and a new callback was added that will
           always execute at the end of the request, independent on if an
           error occurred or not.  See :ref:`callbacks-and-errors`.


        :param environ: a WSGI environment
        :param start_response: a callable accepting a status code,
                               a list of headers and an optional
                               exception context to start the response
        """
        ctx = self.request_context(environ)
        ctx.push()
        error = None
        try:
            try:
                response = self.full_dispatch_request()
            except Exception as e:
                error = e
                response = self.make_response(self.handle_exception(e))
            return response(environ, start_response)
        finally:
            if self.should_ignore_error(error):
                error = None
            ctx.auto_pop(error)
#创建一个wsgi应用的函数,主要用于将app用于正式部署


    @property
    def modules(self):
        from warnings import warn
        warn(DeprecationWarning('Flask.modules is deprecated, use '
                                'Flask.blueprints instead'), stacklevel=2)
        return self.blueprints
#弃用属性modules,发出警告并返回blueprints


    def __call__(self, environ, start_response):
        """Shortcut for :attr:`wsgi_app`."""
        return self.wsgi_app(environ, start_response)
#当实例当做函数使用时,调用的实际是wsgi_app函数


    def __repr__(self):
        return '<%s %r>' % (
            self.__class__.__name__,
            self.name,
        )
#自身的在python shell中的显示

你可能感兴趣的:(Flask,Web开发笔记,python,Flask,web开发,源码)