wrappers.py

Official Document

Implements the WSGI wrappers (request and response).

Overview

This module implements custom request and response objects. Now we are closed to the core part of Flask object.

Details

JSONMixin

Below is the document of on_json_loading_failed method in werkzeug.

Called if get_json() parsing fails and isn’t silenced. If this method returns a value, it is used as the return value for get_json(). The default implementation raises BadRequest.

Note that the override method on_json_loading_failed adds some additional information when Flask application is in debug mode.

from werkzeug.exceptions import BadRequest
from werkzeug.wrappers.json import JSONMixin as _JSONMixin
from . import json
from .globals import current_app

class JSONMixin(_JSONMixin):
    json_module = json

    def on_json_loading_failed(self, e):
        if current_app and current_app.debug:
            raise BadRequest("Failed to decode JSON object: {0}".format(e))

        raise BadRequest()

Request

The class Request is a subclass of RequestBase and JSONMixin, click here to find details about werkzeug.wrappers.Request. Simply speaking, the subclassed Request has some new properties, and the basic functions are the same as werkzeug.wrappers.Request.

from werkzeug.wrappers import Request as RequestBase

class Request(RequestBase, JSONMixin):
    url_rule = None

    view_args = None

    routing_exception = None

The property max_content_length returns MAX_CONTENT_LENGTH of the current app, and it returns None if this variable does not exist.

@property
    def max_content_length(self):
        if current_app:
            return current_app.config["MAX_CONTENT_LENGTH"]

The property endpoint returns self.url_rule.endpoint, and it returns None if self.url_rule is None.

@property
    def endpoint(self):
        if self.url_rule is not None:
            return self.url_rule.endpoint

The property blueprint returns the “front” part of the endpoint. For example, if self.url_rule.endpoint is foo.bar.html, then it return foo.bar. Click here to find the description of rsplit.

@property
    def blueprint(self):
        if self.url_rule and "." in self.url_rule.endpoint:
            return self.url_rule.endpoint.rsplit(".", 1)[0]

The method _load_form_data does almost the same as its base class, and the only difference is a special processing in debug mode, and the method attach_enctype_error_multidict will be explained in the debughelpers.py chapter.

def _load_form_data(self):
        RequestBase._load_form_data(self)

        # In debug mode we're replacing the files multidict with an ad-hoc
        # subclass that raises a different error for key errors.
        if (
            current_app
            and current_app.debug
            and self.mimetype != "multipart/form-data"
            and not self.files
        ):
            from .debughelpers import attach_enctype_error_multidict

            attach_enctype_error_multidict(self)

Source Code

# -*- coding: utf-8 -*-
"""
    flask.wrappers
    ~~~~~~~~~~~~~~

    Implements the WSGI wrappers (request and response).

    :copyright: 2010 Pallets
    :license: BSD-3-Clause
"""
from werkzeug.exceptions import BadRequest
from werkzeug.wrappers import Request as RequestBase
from werkzeug.wrappers import Response as ResponseBase
from werkzeug.wrappers.json import JSONMixin as _JSONMixin

from . import json
from .globals import current_app


class JSONMixin(_JSONMixin):
    json_module = json

    def on_json_loading_failed(self, e):
        if current_app and current_app.debug:
            raise BadRequest("Failed to decode JSON object: {0}".format(e))

        raise BadRequest()


class Request(RequestBase, JSONMixin):
    """The request object used by default in Flask.  Remembers the
    matched endpoint and view arguments.

    It is what ends up as :class:`~flask.request`.  If you want to replace
    the request object used you can subclass this and set
    :attr:`~flask.Flask.request_class` to your subclass.

    The request object is a :class:`~werkzeug.wrappers.Request` subclass and
    provides all of the attributes Werkzeug defines plus a few Flask
    specific ones.
    """

    #: The internal URL rule that matched the request.  This can be
    #: useful to inspect which methods are allowed for the URL from
    #: a before/after handler (``request.url_rule.methods``) etc.
    #: Though if the request's method was invalid for the URL rule,
    #: the valid list is available in ``routing_exception.valid_methods``
    #: instead (an attribute of the Werkzeug exception
    #: :exc:`~werkzeug.exceptions.MethodNotAllowed`)
    #: because the request was never internally bound.
    #:
    #: .. versionadded:: 0.6
    url_rule = None

    #: A dict of view arguments that matched the request.  If an exception
    #: happened when matching, this will be ``None``.
    view_args = None

    #: If matching the URL failed, this is the exception that will be
    #: raised / was raised as part of the request handling.  This is
    #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or
    #: something similar.
    routing_exception = None

    @property
    def max_content_length(self):
        """Read-only view of the ``MAX_CONTENT_LENGTH`` config key."""
        if current_app:
            return current_app.config["MAX_CONTENT_LENGTH"]

    @property
    def endpoint(self):
        """The endpoint that matched the request.  This in combination with
        :attr:`view_args` can be used to reconstruct the same or a
        modified URL.  If an exception happened when matching, this will
        be ``None``.
        """
        if self.url_rule is not None:
            return self.url_rule.endpoint

    @property
    def blueprint(self):
        """The name of the current blueprint"""
        if self.url_rule and "." in self.url_rule.endpoint:
            return self.url_rule.endpoint.rsplit(".", 1)[0]

    def _load_form_data(self):
        RequestBase._load_form_data(self)

        # In debug mode we're replacing the files multidict with an ad-hoc
        # subclass that raises a different error for key errors.
        if (
            current_app
            and current_app.debug
            and self.mimetype != "multipart/form-data"
            and not self.files
        ):
            from .debughelpers import attach_enctype_error_multidict

            attach_enctype_error_multidict(self)


class Response(ResponseBase, JSONMixin):
    """The response object that is used by default in Flask.  Works like the
    response object from Werkzeug but is set to have an HTML mimetype by
    default.  Quite often you don't have to create this object yourself because
    :meth:`~flask.Flask.make_response` will take care of that for you.

    If you want to replace the response object used you can subclass this and
    set :attr:`~flask.Flask.response_class` to your subclass.

    .. versionchanged:: 1.0
        JSON support is added to the response, like the request. This is useful
        when testing to get the test client response data as JSON.

    .. versionchanged:: 1.0

        Added :attr:`max_cookie_size`.
    """

    default_mimetype = "text/html"

    def _get_data_for_json(self, cache):
        return self.get_data()

    @property
    def max_cookie_size(self):
        """Read-only view of the :data:`MAX_COOKIE_SIZE` config key.

        See :attr:`~werkzeug.wrappers.BaseResponse.max_cookie_size` in
        Werkzeug's docs.
        """
        if current_app:
            return current_app.config["MAX_COOKIE_SIZE"]

        # return Werkzeug's default when not in an app context
        return super(Response, self).max_cookie_size