diff options
author | James Taylor <user234683@users.noreply.github.com> | 2019-08-09 22:01:04 -0700 |
---|---|---|
committer | James Taylor <user234683@users.noreply.github.com> | 2019-08-09 22:01:04 -0700 |
commit | 2e75c6d9603f8a5edf6495f8d4fb3115a67d823c (patch) | |
tree | 8fb2d1bec2cf0e50c5fce6bc718f755485419db0 /python/flask/wrappers.py | |
parent | cc9283ad5332f59a69a91d9d0fab299779de513c (diff) | |
parent | adc40bc760345a23678a01f27d7697dfd3811914 (diff) | |
download | yt-local-2e75c6d9603f8a5edf6495f8d4fb3115a67d823c.tar.lz yt-local-2e75c6d9603f8a5edf6495f8d4fb3115a67d823c.tar.xz yt-local-2e75c6d9603f8a5edf6495f8d4fb3115a67d823c.zip |
Merge flask framework and other stuff from master
Diffstat (limited to 'python/flask/wrappers.py')
-rw-r--r-- | python/flask/wrappers.py | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/python/flask/wrappers.py b/python/flask/wrappers.py new file mode 100644 index 0000000..12eff2c --- /dev/null +++ b/python/flask/wrappers.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +""" + flask.wrappers + ~~~~~~~~~~~~~~ + + Implements the WSGI wrappers (request and response). + + :copyright: © 2010 by the Pallets team. + :license: BSD, see LICENSE for more details. +""" + +from werkzeug.exceptions import BadRequest +from werkzeug.wrappers import Request as RequestBase, Response as ResponseBase + +from flask import json +from flask.globals import current_app + + +class JSONMixin(object): + """Common mixin for both request and response objects to provide JSON + parsing capabilities. + + .. versionadded:: 1.0 + """ + + _cached_json = (Ellipsis, Ellipsis) + + @property + def is_json(self): + """Check if the mimetype indicates JSON data, either + :mimetype:`application/json` or :mimetype:`application/*+json`. + + .. versionadded:: 0.11 + """ + mt = self.mimetype + return ( + mt == 'application/json' + or (mt.startswith('application/')) and mt.endswith('+json') + ) + + @property + def json(self): + """This will contain the parsed JSON data if the mimetype indicates + JSON (:mimetype:`application/json`, see :meth:`is_json`), otherwise it + will be ``None``. + """ + return self.get_json() + + def _get_data_for_json(self, cache): + return self.get_data(cache=cache) + + def get_json(self, force=False, silent=False, cache=True): + """Parse and return the data as JSON. If the mimetype does not + indicate JSON (:mimetype:`application/json`, see + :meth:`is_json`), this returns ``None`` unless ``force`` is + true. If parsing fails, :meth:`on_json_loading_failed` is called + and its return value is used as the return value. + + :param force: Ignore the mimetype and always try to parse JSON. + :param silent: Silence parsing errors and return ``None`` + instead. + :param cache: Store the parsed JSON to return for subsequent + calls. + """ + if cache and self._cached_json[silent] is not Ellipsis: + return self._cached_json[silent] + + if not (force or self.is_json): + return None + + data = self._get_data_for_json(cache=cache) + + try: + rv = json.loads(data) + except ValueError as e: + if silent: + rv = None + if cache: + normal_rv, _ = self._cached_json + self._cached_json = (normal_rv, rv) + else: + rv = self.on_json_loading_failed(e) + if cache: + _, silent_rv = self._cached_json + self._cached_json = (rv, silent_rv) + else: + if cache: + self._cached_json = (rv, rv) + + return rv + + def on_json_loading_failed(self, e): + """Called if :meth:`get_json` parsing fails and isn't silenced. If + this method returns a value, it is used as the return value for + :meth:`get_json`. The default implementation raises a + :class:`BadRequest` exception. + + .. versionchanged:: 0.10 + Raise a :exc:`BadRequest` error instead of returning an error + message as JSON. If you want that behavior you can add it by + subclassing. + + .. versionadded:: 0.8 + """ + if current_app is not None 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 |