Merge pull request #3894 from pallets/update-werkzeug

Update for recent changes in Pallets libraries
This commit is contained in:
David Lord 2021-02-01 19:20:20 -08:00 committed by GitHub
commit 9f7ac04aaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 59 additions and 79 deletions

View file

@ -49,7 +49,8 @@ Unreleased
implementations in ``werkzeug.utils``. :pr:`3828`
- Some ``send_file`` parameters have been renamed, the old names are
deprecated. ``attachment_filename`` is renamed to ``download_name``.
``cache_timeout`` is renamed to ``max_age``. :pr:`3828`
``cache_timeout`` is renamed to ``max_age``. ``add_etags`` is
renamed to ``etag``. :pr:`3828, 3883`
- ``send_file`` passes ``download_name`` even if
``as_attachment=False`` by using ``Content-Disposition: inline``.
:pr:`3828`

View file

@ -27,9 +27,9 @@ Incoming Request Data
---------------------
.. autoclass:: Request
:members:
:inherited-members:
:exclude-members: json_module
:members:
:inherited-members:
:exclude-members: json_module
.. attribute:: request
@ -48,20 +48,9 @@ Response Objects
----------------
.. autoclass:: flask.Response
:members: set_cookie, max_cookie_size, data, mimetype, is_json, get_json
.. attribute:: headers
A :class:`~werkzeug.datastructures.Headers` object representing the response headers.
.. attribute:: status
A string with a response status.
.. attribute:: status_code
The response status as integer.
:members:
:inherited-members:
:exclude-members: json_module
Sessions
--------

View file

@ -249,25 +249,11 @@ be passed an instance of ``InternalServerError``, not the original
unhandled error.
The original error is available as ``e.original_exception``.
Until Werkzeug 1.0.0, this attribute will only exist during unhandled
errors, use ``getattr`` to get access it for compatibility.
.. code-block:: python
@app.errorhandler(InternalServerError)
def handle_500(e):
original = getattr(e, "original_exception", None)
if original is None:
# direct 500 error, such as abort(500)
return render_template("500.html"), 500
# wrapped unhandled error
return render_template("500_unhandled.html", e=original), 500
An error handler for "500 Internal Server Error" will be passed uncaught exceptions in
addition to explicit 500 errors. In debug mode, a handler for "500 Internal Server Error" will not be used.
Instead, the interactive debugger will be shown.
An error handler for "500 Internal Server Error" will be passed uncaught
exceptions in addition to explicit 500 errors. In debug mode, a handler
for "500 Internal Server Error" will not be used. Instead, the
interactive debugger will be shown.
Custom Error Pages

View file

@ -119,7 +119,7 @@ Notice that our test functions begin with the word `test`; this allows
By using ``client.get`` we can send an HTTP ``GET`` request to the
application with the given path. The return value will be a
:class:`~flask.Flask.response_class` object. We can now use the
:attr:`~werkzeug.wrappers.BaseResponse.data` attribute to inspect
:attr:`~werkzeug.wrappers.Response.data` attribute to inspect
the return value (as string) from the application.
In this case, we ensure that ``'No entries here so far'``
is part of the output.

View file

@ -302,7 +302,7 @@ URL when the register view redirects to the login view.
:attr:`~Response.data` contains the body of the response as bytes. If
you expect a certain value to render on the page, check that it's in
``data``. Bytes must be compared to bytes. If you want to compare text,
use :meth:`get_data(as_text=True) <werkzeug.wrappers.BaseResponse.get_data>`
use :meth:`get_data(as_text=True) <werkzeug.wrappers.Response.get_data>`
instead.
``pytest.mark.parametrize`` tells Pytest to run the same test function

View file

@ -1,3 +1,3 @@
from .cli import main
main(as_module=True)
main()

View file

@ -16,7 +16,7 @@ from werkzeug.routing import Map
from werkzeug.routing import RequestRedirect
from werkzeug.routing import RoutingException
from werkzeug.routing import Rule
from werkzeug.wrappers import BaseResponse
from werkzeug.wrappers import Response as BaseResponse
from . import cli
from . import json
@ -278,7 +278,7 @@ class Flask(Scaffold):
#: This is a ``dict`` instead of an ``ImmutableDict`` to allow
#: easier configuration.
#:
jinja_options = {"extensions": ["jinja2.ext.autoescape", "jinja2.ext.with_"]}
jinja_options = {}
#: Default configuration parameters.
default_config = ImmutableDict(
@ -1386,17 +1386,10 @@ class Flask(Scaffold):
.. versionadded:: 0.7
"""
if isinstance(e, BadRequestKeyError):
if self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]:
e.show_exception = True
# Werkzeug < 0.15 doesn't add the KeyError to the 400
# message, add it in manually.
# TODO: clean up once Werkzeug >= 0.15.5 is required
if e.args[0] not in e.get_description():
e.description = f"KeyError: {e.args[0]!r}"
elif not hasattr(BadRequestKeyError, "show_exception"):
e.args = ()
if isinstance(e, BadRequestKeyError) and (
self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]
):
e.show_exception = True
if isinstance(e, HTTPException) and not self.trap_http_exception(e):
return self.handle_http_exception(e)
@ -1454,10 +1447,7 @@ class Flask(Scaffold):
raise e
self.log_exception(exc_info)
server_error = InternalServerError()
# TODO: pass as param when Werkzeug>=1.0.0 is required
# TODO: also remove note about this from docstring and docs
server_error.original_exception = e
server_error = InternalServerError(original_exception=e)
handler = self._find_error_handler(server_error)
if handler is not None:

View file

@ -953,10 +953,10 @@ debug mode.
)
def main(as_module=False):
def main():
# TODO omit sys.argv once https://github.com/pallets/click/issues/536 is fixed
cli.main(args=sys.argv[1:], prog_name="python -m flask" if as_module else None)
cli.main(args=sys.argv[1:])
if __name__ == "__main__":
main(as_module=True)
main()

View file

@ -439,6 +439,8 @@ def get_flashed_messages(with_categories=False, category_filter=()):
def _prepare_send_file_kwargs(
download_name=None,
attachment_filename=None,
etag=None,
add_etags=None,
max_age=None,
cache_timeout=None,
**kwargs,
@ -461,12 +463,22 @@ def _prepare_send_file_kwargs(
)
max_age = cache_timeout
if add_etags is not None:
warnings.warn(
"The 'add_etags' parameter has been renamed to 'etag'. The old name will be"
" removed in Flask 2.1.",
DeprecationWarning,
stacklevel=3,
)
etag = add_etags
if max_age is None:
max_age = current_app.get_send_file_max_age
kwargs.update(
environ=request.environ,
download_name=download_name,
etag=etag,
max_age=max_age,
use_x_sendfile=current_app.use_x_sendfile,
response_class=current_app.response_class,
@ -482,7 +494,8 @@ def send_file(
download_name=None,
attachment_filename=None,
conditional=True,
add_etags=True,
etag=True,
add_etags=None,
last_modified=None,
max_age=None,
cache_timeout=None,
@ -518,8 +531,8 @@ def send_file(
the file. Defaults to the passed file name.
:param conditional: Enable conditional and range responses based on
request headers. Requires passing a file path and ``environ``.
:param add_etags: Calculate an ETag for the file. Requires passing a
file path.
:param etag: Calculate an ETag for the file, which requires passing
a file path. Can also be a string to use instead.
:param last_modified: The last modified time to send for the file,
in seconds. If not provided, it will try to detect it from the
file path.
@ -537,6 +550,10 @@ def send_file(
``conditional`` is enabled and ``max_age`` is not set by
default.
.. versionchanged:: 2.0.0
``etag`` replaces the ``add_etags`` parameter. It can be a
string to use instead of generating one.
.. versionchanged:: 2.0
Passing a file-like object that inherits from
:class:`~io.TextIOBase` will raise a :exc:`ValueError` rather
@ -593,6 +610,7 @@ def send_file(
download_name=download_name,
attachment_filename=attachment_filename,
conditional=conditional,
etag=etag,
add_etags=add_etags,
last_modified=last_modified,
max_age=max_age,

View file

@ -5,7 +5,7 @@ import werkzeug.test
from click.testing import CliRunner
from werkzeug.test import Client
from werkzeug.urls import url_parse
from werkzeug.wrappers import BaseRequest
from werkzeug.wrappers import Request as BaseRequest
from . import _request_ctx_stack
from .cli import ScriptInfo

View file

@ -1,23 +1,12 @@
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(f"Failed to decode JSON object: {e}")
raise BadRequest()
class Request(RequestBase, JSONMixin):
class Request(RequestBase):
"""The request object used by default in Flask. Remembers the
matched endpoint and view arguments.
@ -30,6 +19,8 @@ class Request(RequestBase, JSONMixin):
specific ones.
"""
json_module = json
#: 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.
@ -89,8 +80,14 @@ class Request(RequestBase, JSONMixin):
attach_enctype_error_multidict(self)
def on_json_loading_failed(self, e):
if current_app and current_app.debug:
raise BadRequest(f"Failed to decode JSON object: {e}")
class Response(JSONMixin, ResponseBase):
raise BadRequest()
class Response(ResponseBase):
"""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
@ -110,14 +107,13 @@ class Response(JSONMixin, ResponseBase):
default_mimetype = "text/html"
def _get_data_for_json(self, cache):
return self.get_data()
json_module = json
@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
See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in
Werkzeug's docs.
"""
if current_app: