From 0ce270d1f3615f222226fb316e505a60c1e3baab Mon Sep 17 00:00:00 2001 From: laggardkernel Date: Wed, 12 May 2021 05:44:00 +0800 Subject: [PATCH 001/109] Update doc about minimal Python version for async support --- docs/async-await.rst | 3 ++- docs/installation.rst | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/async-await.rst b/docs/async-await.rst index 34751d47..ad7cbf38 100644 --- a/docs/async-await.rst +++ b/docs/async-await.rst @@ -7,7 +7,8 @@ Using ``async`` and ``await`` Routes, error handlers, before request, after request, and teardown functions can all be coroutine functions if Flask is installed with the -``async`` extra (``pip install flask[async]``). This allows views to be +``async`` extra (``pip install flask[async]``). It requires Python 3.7+ +where ``contextvars.ContextVar`` is available. This allows views to be defined with ``async def`` and use ``await``. .. code-block:: python diff --git a/docs/installation.rst b/docs/installation.rst index aef7df0c..a5d105f7 100644 --- a/docs/installation.rst +++ b/docs/installation.rst @@ -8,6 +8,8 @@ Python Version We recommend using the latest version of Python. Flask supports Python 3.6 and newer. +``async`` support in Flask requires Python 3.7+ for ``contextvars.ContextVar``. + Dependencies ------------ From 491ea32803cb05fb8fc4dfb81ec6c96f94529eb0 Mon Sep 17 00:00:00 2001 From: laggardkernel Date: Tue, 1 Jun 2021 13:43:28 +0800 Subject: [PATCH 002/109] Optimize loop in Flask._find_error_handler() --- src/flask/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flask/app.py b/src/flask/app.py index cacb40a5..f6656458 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -1276,7 +1276,7 @@ class Flask(Scaffold): """ exc_class, code = self._get_exc_class_and_code(type(e)) - for c in [code, None]: + for c in [code, None] if code is not None else [None]: for name in chain(request.blueprints, [None]): handler_map = self.error_handler_spec[name][c] From 270eb2df2a1606383f50ff079a32240966b43fbc Mon Sep 17 00:00:00 2001 From: Miguel Grinberg Date: Fri, 28 May 2021 00:01:48 +0100 Subject: [PATCH 003/109] Support View and MethodView instances with async handlers --- CHANGES.rst | 1 + docs/async-await.rst | 6 ++++++ src/flask/views.py | 5 +++-- tests/test_async.py | 25 ++++++++++++++++++++++++- 4 files changed, 34 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 7920e5ab..be263970 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -10,6 +10,7 @@ Unreleased decorators. :issue:`4104` - Fixed the issue where typing requires template global decorators to accept functions with no arguments. :issue:`4098` +- Support View and MethodView instances with async handlers. :issue:`4112` Version 2.0.1 diff --git a/docs/async-await.rst b/docs/async-await.rst index ad7cbf38..71e5f452 100644 --- a/docs/async-await.rst +++ b/docs/async-await.rst @@ -18,6 +18,12 @@ defined with ``async def`` and use ``await``. data = await async_db_query(...) return jsonify(data) +Pluggable class-based views also support handlers that are implemented as +coroutines. This applies to the :meth:`~flask.views.View.dispatch_request` +method in views that inherit from the :class:`flask.views.View` class, as +well as all the HTTP method handlers in views that inherit from the +:class:`flask.views.MethodView` class. + .. admonition:: Using ``async`` on Windows on Python 3.8 Python 3.8 has a bug related to asyncio on Windows. If you encounter diff --git a/src/flask/views.py b/src/flask/views.py index 339ffa18..1bd5c68b 100644 --- a/src/flask/views.py +++ b/src/flask/views.py @@ -1,5 +1,6 @@ import typing as t +from .globals import current_app from .globals import request from .typing import ResponseReturnValue @@ -80,7 +81,7 @@ class View: def view(*args: t.Any, **kwargs: t.Any) -> ResponseReturnValue: self = view.view_class(*class_args, **class_kwargs) # type: ignore - return self.dispatch_request(*args, **kwargs) + return current_app.ensure_sync(self.dispatch_request)(*args, **kwargs) if cls.decorators: view.__name__ = name @@ -154,4 +155,4 @@ class MethodView(View, metaclass=MethodViewType): meth = getattr(self, "get", None) assert meth is not None, f"Unimplemented method {request.method!r}" - return meth(*args, **kwargs) + return current_app.ensure_sync(meth)(*args, **kwargs) diff --git a/tests/test_async.py b/tests/test_async.py index 26a91118..344e9fe6 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -6,6 +6,8 @@ import pytest from flask import Blueprint from flask import Flask from flask import request +from flask.views import MethodView +from flask.views import View pytest.importorskip("asgiref") @@ -18,6 +20,24 @@ class BlueprintError(Exception): pass +class AsyncView(View): + methods = ["GET", "POST"] + + async def dispatch_request(self): + await asyncio.sleep(0) + return request.method + + +class AsyncMethodView(MethodView): + async def get(self): + await asyncio.sleep(0) + return 'GET' + + async def post(self): + await asyncio.sleep(0) + return 'POST' + + @pytest.fixture(name="async_app") def _async_app(): app = Flask(__name__) @@ -53,11 +73,14 @@ def _async_app(): app.register_blueprint(blueprint, url_prefix="/bp") + app.add_url_rule('/view', view_func=AsyncView.as_view('view')) + app.add_url_rule('/methodview', view_func=AsyncMethodView.as_view('methodview')) + return app @pytest.mark.skipif(sys.version_info < (3, 7), reason="requires Python >= 3.7") -@pytest.mark.parametrize("path", ["/", "/home", "/bp/"]) +@pytest.mark.parametrize("path", ["/", "/home", "/bp/", "/view", "/methodview"]) def test_async_route(path, async_app): test_client = async_app.test_client() response = test_client.get(path) From 5205cd4ea979f6c322e4e6a256a72e7808592818 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 17:56:33 +0000 Subject: [PATCH 004/109] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_async.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_async.py b/tests/test_async.py index 344e9fe6..8276c4a8 100644 --- a/tests/test_async.py +++ b/tests/test_async.py @@ -31,11 +31,11 @@ class AsyncView(View): class AsyncMethodView(MethodView): async def get(self): await asyncio.sleep(0) - return 'GET' + return "GET" async def post(self): await asyncio.sleep(0) - return 'POST' + return "POST" @pytest.fixture(name="async_app") @@ -73,8 +73,8 @@ def _async_app(): app.register_blueprint(blueprint, url_prefix="/bp") - app.add_url_rule('/view', view_func=AsyncView.as_view('view')) - app.add_url_rule('/methodview', view_func=AsyncMethodView.as_view('methodview')) + app.add_url_rule("/view", view_func=AsyncView.as_view("view")) + app.add_url_rule("/methodview", view_func=AsyncMethodView.as_view("methodview")) return app From 6a4e7e948d7e5bd5b2b76c1b7f1a0392644bee1e Mon Sep 17 00:00:00 2001 From: Pascal Corpet Date: Mon, 31 May 2021 12:28:44 +0200 Subject: [PATCH 005/109] improve typing for `app.errorhandler` decorator --- CHANGES.rst | 1 + src/flask/app.py | 6 ++++-- src/flask/blueprints.py | 6 ++++-- src/flask/scaffold.py | 27 +++++++++++++++++++-------- src/flask/typing.py | 11 ++++++++++- 5 files changed, 38 insertions(+), 13 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index be263970..d8dd974f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -11,6 +11,7 @@ Unreleased - Fixed the issue where typing requires template global decorators to accept functions with no arguments. :issue:`4098` - Support View and MethodView instances with async handlers. :issue:`4112` +- Enhance typing of ``app.errorhandler`` decorator. :issue:`4095` Version 2.0.1 diff --git a/src/flask/app.py b/src/flask/app.py index f6656458..22cc9abc 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -61,7 +61,6 @@ from .templating import Environment from .typing import AfterRequestCallable from .typing import BeforeFirstRequestCallable from .typing import BeforeRequestCallable -from .typing import ErrorHandlerCallable from .typing import ResponseReturnValue from .typing import TeardownCallable from .typing import TemplateContextProcessorCallable @@ -78,6 +77,7 @@ if t.TYPE_CHECKING: from .blueprints import Blueprint from .testing import FlaskClient from .testing import FlaskCliRunner + from .typing import ErrorHandlerCallable if sys.version_info >= (3, 8): iscoroutinefunction = inspect.iscoroutinefunction @@ -1268,7 +1268,9 @@ class Flask(Scaffold): self.shell_context_processors.append(f) return f - def _find_error_handler(self, e: Exception) -> t.Optional[ErrorHandlerCallable]: + def _find_error_handler( + self, e: Exception + ) -> t.Optional["ErrorHandlerCallable[Exception]"]: """Return a registered error handler for an exception in this order: blueprint handler for a specific code, app handler for a specific code, blueprint handler for an exception class, app handler for an exception diff --git a/src/flask/blueprints.py b/src/flask/blueprints.py index 883fc2ff..8241420b 100644 --- a/src/flask/blueprints.py +++ b/src/flask/blueprints.py @@ -8,7 +8,6 @@ from .scaffold import Scaffold from .typing import AfterRequestCallable from .typing import BeforeFirstRequestCallable from .typing import BeforeRequestCallable -from .typing import ErrorHandlerCallable from .typing import TeardownCallable from .typing import TemplateContextProcessorCallable from .typing import TemplateFilterCallable @@ -19,6 +18,7 @@ from .typing import URLValuePreprocessorCallable if t.TYPE_CHECKING: from .app import Flask + from .typing import ErrorHandlerCallable DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable] @@ -581,7 +581,9 @@ class Blueprint(Scaffold): handler is used for all requests, even if outside of the blueprint. """ - def decorator(f: ErrorHandlerCallable) -> ErrorHandlerCallable: + def decorator( + f: "ErrorHandlerCallable[Exception]", + ) -> "ErrorHandlerCallable[Exception]": self.record_once(lambda s: s.app.errorhandler(code)(f)) return f diff --git a/src/flask/scaffold.py b/src/flask/scaffold.py index 239bc46a..e80e1915 100644 --- a/src/flask/scaffold.py +++ b/src/flask/scaffold.py @@ -21,7 +21,7 @@ from .templating import _default_template_ctx_processor from .typing import AfterRequestCallable from .typing import AppOrBlueprintKey from .typing import BeforeRequestCallable -from .typing import ErrorHandlerCallable +from .typing import GenericException from .typing import TeardownCallable from .typing import TemplateContextProcessorCallable from .typing import URLDefaultCallable @@ -29,6 +29,7 @@ from .typing import URLValuePreprocessorCallable if t.TYPE_CHECKING: from .wrappers import Response + from .typing import ErrorHandlerCallable # a singleton sentinel value for parameter defaults _sentinel = object() @@ -144,7 +145,10 @@ class Scaffold: #: directly and its format may change at any time. self.error_handler_spec: t.Dict[ AppOrBlueprintKey, - t.Dict[t.Optional[int], t.Dict[t.Type[Exception], ErrorHandlerCallable]], + t.Dict[ + t.Optional[int], + t.Dict[t.Type[Exception], "ErrorHandlerCallable[Exception]"], + ], ] = defaultdict(lambda: defaultdict(dict)) #: A data structure of functions to call at the beginning of @@ -643,8 +647,11 @@ class Scaffold: @setupmethod def errorhandler( - self, code_or_exception: t.Union[t.Type[Exception], int] - ) -> t.Callable[[ErrorHandlerCallable], ErrorHandlerCallable]: + self, code_or_exception: t.Union[t.Type[GenericException], int] + ) -> t.Callable[ + ["ErrorHandlerCallable[GenericException]"], + "ErrorHandlerCallable[GenericException]", + ]: """Register a function to handle errors by code or exception class. A decorator that is used to register a function given an @@ -674,7 +681,9 @@ class Scaffold: an arbitrary exception """ - def decorator(f: ErrorHandlerCallable) -> ErrorHandlerCallable: + def decorator( + f: "ErrorHandlerCallable[GenericException]", + ) -> "ErrorHandlerCallable[GenericException]": self.register_error_handler(code_or_exception, f) return f @@ -683,8 +692,8 @@ class Scaffold: @setupmethod def register_error_handler( self, - code_or_exception: t.Union[t.Type[Exception], int], - f: ErrorHandlerCallable, + code_or_exception: t.Union[t.Type[GenericException], int], + f: "ErrorHandlerCallable[GenericException]", ) -> None: """Alternative error attach function to the :meth:`errorhandler` decorator that is more straightforward to use for non decorator @@ -708,7 +717,9 @@ class Scaffold: " instead." ) - self.error_handler_spec[None][code][exc_class] = f + self.error_handler_spec[None][code][exc_class] = t.cast( + "ErrorHandlerCallable[Exception]", f + ) @staticmethod def _get_exc_class_and_code( diff --git a/src/flask/typing.py b/src/flask/typing.py index b1a6cbdc..f1c84670 100644 --- a/src/flask/typing.py +++ b/src/flask/typing.py @@ -33,11 +33,12 @@ ResponseReturnValue = t.Union[ "WSGIApplication", ] +GenericException = t.TypeVar("GenericException", bound=Exception, contravariant=True) + AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named AfterRequestCallable = t.Callable[["Response"], "Response"] BeforeFirstRequestCallable = t.Callable[[], None] BeforeRequestCallable = t.Callable[[], t.Optional[ResponseReturnValue]] -ErrorHandlerCallable = t.Callable[[Exception], ResponseReturnValue] TeardownCallable = t.Callable[[t.Optional[BaseException]], None] TemplateContextProcessorCallable = t.Callable[[], t.Dict[str, t.Any]] TemplateFilterCallable = t.Callable[..., t.Any] @@ -45,3 +46,11 @@ TemplateGlobalCallable = t.Callable[..., t.Any] TemplateTestCallable = t.Callable[..., bool] URLDefaultCallable = t.Callable[[str, dict], None] URLValuePreprocessorCallable = t.Callable[[t.Optional[str], t.Optional[dict]], None] + + +if t.TYPE_CHECKING: + import typing_extensions as te + + class ErrorHandlerCallable(te.Protocol[GenericException]): + def __call__(self, error: GenericException) -> ResponseReturnValue: + ... From 63893a427bd022d192febadad0b31ae06fa80776 Mon Sep 17 00:00:00 2001 From: pgjones Date: Sun, 6 Jun 2021 11:09:03 +0100 Subject: [PATCH 006/109] Improve the changelog entry The fix to the teardown_request also applies to all teardown_* methods. --- CHANGES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES.rst b/CHANGES.rst index d8dd974f..c27b623f 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,7 +5,7 @@ Version 2.0.2 Unreleased -- Fix type annotation for ``teardown_request``. :issue:`4093` +- Fix type annotation for ``teardown_*`` methods. :issue:`4093` - Fix type annotation for ``before_request`` and ``before_app_request`` decorators. :issue:`4104` - Fixed the issue where typing requires template global From 92bed6619459da93f79e85ec674b24cb6fa322f6 Mon Sep 17 00:00:00 2001 From: Hugo Montenegro Date: Tue, 8 Jun 2021 19:01:07 +0200 Subject: [PATCH 007/109] Update celery.rst small typo --- docs/patterns/celery.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/patterns/celery.rst b/docs/patterns/celery.rst index e1f6847e..38a9a025 100644 --- a/docs/patterns/celery.rst +++ b/docs/patterns/celery.rst @@ -64,7 +64,7 @@ An example task Let's write a task that adds two numbers together and returns the result. We configure Celery's broker and backend to use Redis, create a ``celery`` -application using the factor from above, and then use it to define the task. :: +application using the factory from above, and then use it to define the task. :: from flask import Flask From 34027d8d876c140f84e18d6b56c0aecc5481874c Mon Sep 17 00:00:00 2001 From: Grey Li Date: Mon, 14 Jun 2021 14:20:04 +0800 Subject: [PATCH 008/109] Improve the contributing guide --- CONTRIBUTING.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3a9177a4..a3c8b851 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -12,14 +12,16 @@ to address bugs and feature requests in Flask itself. Use one of the following resources for questions about using Flask or issues with your own code: -- The ``#get-help`` channel on our Discord chat: +- The ``#questions`` channel on our Discord chat: https://discord.gg/pallets - The mailing list flask@python.org for long term discussion or larger issues. - Ask on `Stack Overflow`_. Search with Google first using: ``site:stackoverflow.com flask {search term, exception message, etc.}`` +- Ask on our `GitHub Discussions`_. .. _Stack Overflow: https://stackoverflow.com/questions/tagged/flask?tab=Frequent +.. _GitHub Discussions: https://github.com/pallets/flask/discussions Reporting issues @@ -92,7 +94,7 @@ First time setup .. code-block:: text - git remote add fork https://github.com/{username}/flask + $ git remote add fork https://github.com/{username}/flask - Create a virtualenv. From a44c7228600044f530856a33c7da147c528644ff Mon Sep 17 00:00:00 2001 From: pgjones Date: Sat, 5 Jun 2021 16:08:51 +0100 Subject: [PATCH 009/109] Fix registering a blueprint twice with differing names Previously the blueprint recorded aspects (before request, after request etc) would only be added to the app if it was the first registration of the blueprint instance. However only the record-once aspects (app-before requests, app-after request) should be added once on registration of the instance, whereas everything else should be added on every unique name registration. This ensures that these trigger under the new name as well as the old. --- CHANGES.rst | 1 + src/flask/blueprints.py | 8 +++++--- tests/test_blueprints.py | 10 ++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index c27b623f..bdfa9f01 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -12,6 +12,7 @@ Unreleased decorators to accept functions with no arguments. :issue:`4098` - Support View and MethodView instances with async handlers. :issue:`4112` - Enhance typing of ``app.errorhandler`` decorator. :issue:`4095` +- Fix registering a blueprint twice with differing names. :issue:`4124` Version 2.0.1 diff --git a/src/flask/blueprints.py b/src/flask/blueprints.py index 8241420b..c8ce67a4 100644 --- a/src/flask/blueprints.py +++ b/src/flask/blueprints.py @@ -293,7 +293,6 @@ class Blueprint(Scaffold): Registering the same blueprint with the same name multiple times is deprecated and will become an error in Flask 2.1. """ - first_registration = not any(bp is self for bp in app.blueprints.values()) name_prefix = options.get("name_prefix", "") self_name = options.get("name", self.name) name = f"{name_prefix}.{self_name}".lstrip(".") @@ -318,9 +317,12 @@ class Blueprint(Scaffold): stacklevel=4, ) + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + app.blueprints[name] = self self._got_registered_once = True - state = self.make_setup_state(app, options, first_registration) + state = self.make_setup_state(app, options, first_bp_registration) if self.has_static_folder: state.add_url_rule( @@ -330,7 +332,7 @@ class Blueprint(Scaffold): ) # Merge blueprint data into parent. - if first_registration: + if first_bp_registration or first_name_registration: def extend(bp_dict, parent_dict): for key, values in bp_dict.items(): diff --git a/tests/test_blueprints.py b/tests/test_blueprints.py index 088ad779..a124c612 100644 --- a/tests/test_blueprints.py +++ b/tests/test_blueprints.py @@ -899,6 +899,14 @@ def test_blueprint_renaming(app, client) -> None: def index(): return flask.request.endpoint + @bp.get("/error") + def error(): + flask.abort(403) + + @bp.errorhandler(403) + def forbidden(_: Exception): + return "Error", 403 + @bp2.get("/") def index2(): return flask.request.endpoint @@ -911,3 +919,5 @@ def test_blueprint_renaming(app, client) -> None: assert client.get("/b/").data == b"alt.index" assert client.get("/a/a/").data == b"bp.sub.index2" assert client.get("/b/a/").data == b"alt.sub.index2" + assert client.get("/a/error").data == b"Error" + assert client.get("/b/error").data == b"Error" From f353d126d199071c7933e2f62409e5532333bec5 Mon Sep 17 00:00:00 2001 From: Frank Yu <1032897296@qq.com> Date: Fri, 18 Jun 2021 10:10:29 +0800 Subject: [PATCH 010/109] Update docs of rendering templates (#4153) * Update docs of rendering templates * Improve the grammar Co-authored-by: Grey Li --- docs/quickstart.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 5cd59f41..b5071ab0 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -444,9 +444,9 @@ Here is an example template:

Hello, World!

{% endif %} -Inside templates you also have access to the :class:`~flask.request`, -:class:`~flask.session` and :class:`~flask.g` [#]_ objects -as well as the :func:`~flask.get_flashed_messages` function. +Inside templates you also have access to the :data:`~flask.Flask.config`, +:class:`~flask.request`, :class:`~flask.session` and :class:`~flask.g` [#]_ objects +as well as the :func:`~flask.url_for` and :func:`~flask.get_flashed_messages` functions. Templates are especially useful if inheritance is used. If you want to know how that works, see :doc:`patterns/templateinheritance`. Basically From 5fa7d2efe757e028a734d3dc56e9f13bb812a92a Mon Sep 17 00:00:00 2001 From: Frank Yu Date: Fri, 18 Jun 2021 20:15:02 +0800 Subject: [PATCH 011/109] Update templating.rst --- docs/templating.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templating.rst b/docs/templating.rst index b0964df8..dcc757c3 100644 --- a/docs/templating.rst +++ b/docs/templating.rst @@ -37,7 +37,7 @@ by default: .. data:: config :noindex: - The current configuration object (:data:`flask.config`) + The current configuration object (:data:`flask.Flask.config`) .. versionadded:: 0.6 From 7b696e076a8ebf22e8ad096b7278051d475c88be Mon Sep 17 00:00:00 2001 From: Frank Yu Date: Fri, 18 Jun 2021 22:18:15 +0800 Subject: [PATCH 012/109] Update testing.rst --- docs/testing.rst | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/docs/testing.rst b/docs/testing.rst index 2fedc600..73230b4b 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -48,20 +48,21 @@ the application for testing and initializes a new database:: import pytest from flaskr import create_app + from flaskr.db import init_db @pytest.fixture def client(): - db_fd, flaskr.app.config['DATABASE'] = tempfile.mkstemp() - flaskr.app.config['TESTING'] = True + db_fd, db_path = tempfile.mkstemp() + app = create_app({'TESTING': True, 'DATABASE': db_path}) - with flaskr.app.test_client() as client: - with flaskr.app.app_context(): - flaskr.init_db() + with app.test_client() as client: + with app.app_context(): + init_db() yield client os.close(db_fd) - os.unlink(flaskr.app.config['DATABASE']) + os.unlink(db_path) This client fixture will be called by each individual test. It gives us a simple interface to the application, where we can trigger test requests to the From 35eb582bf3ddbe995681363167eb3233f539ef8b Mon Sep 17 00:00:00 2001 From: Frank Yu Date: Sun, 20 Jun 2021 23:20:14 +0800 Subject: [PATCH 013/109] Change flask.xxx to plain version in testing docs --- docs/testing.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/testing.rst b/docs/testing.rst index 73230b4b..061d46d2 100644 --- a/docs/testing.rst +++ b/docs/testing.rst @@ -225,13 +225,13 @@ temporarily. With this you can access the :class:`~flask.request`, :class:`~flask.g` and :class:`~flask.session` objects like in view functions. Here is a full example that demonstrates this approach:: - import flask + from flask import Flask, request - app = flask.Flask(__name__) + app = Flask(__name__) with app.test_request_context('/?name=Peter'): - assert flask.request.path == '/' - assert flask.request.args['name'] == 'Peter' + assert request.path == '/' + assert request.args['name'] == 'Peter' All the other objects that are context bound can be used in the same way. @@ -248,7 +248,7 @@ the test request context leaves the ``with`` block. If you do want the :meth:`~flask.Flask.before_request` functions to be called as well, you need to call :meth:`~flask.Flask.preprocess_request` yourself:: - app = flask.Flask(__name__) + app = Flask(__name__) with app.test_request_context('/?name=Peter'): app.preprocess_request() @@ -261,7 +261,7 @@ If you want to call the :meth:`~flask.Flask.after_request` functions you need to call into :meth:`~flask.Flask.process_response` which however requires that you pass it a response object:: - app = flask.Flask(__name__) + app = Flask(__name__) with app.test_request_context('/?name=Peter'): resp = Response('...') @@ -330,7 +330,7 @@ context around for a little longer so that additional introspection can happen. With Flask 0.4 this is possible by using the :meth:`~flask.Flask.test_client` with a ``with`` block:: - app = flask.Flask(__name__) + app = Flask(__name__) with app.test_client() as c: rv = c.get('/?tequila=42') @@ -354,7 +354,7 @@ keep the context around and access :data:`flask.session`:: with app.test_client() as c: rv = c.get('/') - assert flask.session['foo'] == 42 + assert session['foo'] == 42 This however does not make it possible to also modify the session or to access the session before a request was fired. Starting with Flask 0.8 we From c224832acccbb9b16485c7adeb7714c71fce1ea8 Mon Sep 17 00:00:00 2001 From: Grey Li Date: Sat, 26 Jun 2021 18:58:15 +0800 Subject: [PATCH 014/109] Fix typo in docs/views.rst --- docs/views.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/views.rst b/docs/views.rst index 1d2daec7..63d26c5c 100644 --- a/docs/views.rst +++ b/docs/views.rst @@ -113,8 +113,8 @@ Method Based Dispatching For RESTful APIs it's especially helpful to execute a different function for each HTTP method. With the :class:`flask.views.MethodView` you can -easily do that. Each HTTP method maps to a function with the same name -(just in lowercase):: +easily do that. Each HTTP method maps to a method of the class with the +same name (just in lowercase):: from flask.views import MethodView From 6fe9235f866fdc9a76cc086bea1512b6825713e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 08:03:44 +0000 Subject: [PATCH 015/109] Bump sphinx-tabs from 3.0.0 to 3.1.0 Bumps [sphinx-tabs](https://github.com/executablebooks/sphinx-tabs) from 3.0.0 to 3.1.0. - [Release notes](https://github.com/executablebooks/sphinx-tabs/releases) - [Changelog](https://github.com/executablebooks/sphinx-tabs/blob/master/CHANGELOG.md) - [Commits](https://github.com/executablebooks/sphinx-tabs/compare/v3.0.0...v3.1.0) --- updated-dependencies: - dependency-name: sphinx-tabs dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements/dev.txt | 34 +++++++++++++++++----------------- requirements/docs.txt | 14 +++++++------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index 42133b83..4603468a 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -9,13 +9,13 @@ alabaster==0.7.12 appdirs==1.4.4 # via virtualenv asgiref==3.3.4 - # via -r tests.in + # via -r requirements/tests.in attrs==21.2.0 # via pytest babel==2.9.1 # via sphinx blinker==1.4 - # via -r tests.in + # via -r requirements/tests.in certifi==2020.12.5 # via requests cfgv==3.3.0 @@ -35,7 +35,7 @@ filelock==3.0.12 # tox # virtualenv greenlet==1.1.0 - # via -r tests.in + # via -r requirements/tests.in identify==2.2.4 # via pre-commit idna==2.10 @@ -48,10 +48,10 @@ jinja2==3.0.1 # via sphinx markupsafe==2.0.1 # via jinja2 +mypy==0.812 + # via -r requirements/typing.in mypy-extensions==0.4.3 # via mypy -mypy==0.812 - # via -r typing.in nodeenv==1.6.0 # via pre-commit packaging==20.9 @@ -61,17 +61,17 @@ packaging==20.9 # sphinx # tox pallets-sphinx-themes==2.0.1 - # via -r docs.in + # via -r requirements/docs.in pep517==0.10.0 # via pip-tools pip-tools==6.1.0 - # via -r dev.in + # via -r requirements/dev.in pluggy==0.13.1 # via # pytest # tox pre-commit==2.13.0 - # via -r dev.in + # via -r requirements/dev.in py==1.10.0 # via # pytest @@ -83,9 +83,9 @@ pygments==2.9.0 pyparsing==2.4.7 # via packaging pytest==6.2.4 - # via -r tests.in + # via -r requirements/tests.in python-dotenv==0.17.1 - # via -r tests.in + # via -r requirements/tests.in pytz==2021.1 # via babel pyyaml==5.4.1 @@ -98,17 +98,17 @@ six==1.16.0 # virtualenv snowballstemmer==2.1.0 # via sphinx -sphinx-issues==1.2.0 - # via -r docs.in -sphinx-tabs==3.0.0 - # via -r docs.in sphinx==4.0.2 # via - # -r docs.in + # -r requirements/docs.in # pallets-sphinx-themes # sphinx-issues # sphinx-tabs # sphinxcontrib-log-cabinet +sphinx-issues==1.2.0 + # via -r requirements/docs.in +sphinx-tabs==3.1.0 + # via -r requirements/docs.in sphinxcontrib-applehelp==1.0.2 # via sphinx sphinxcontrib-devhelp==1.0.2 @@ -118,7 +118,7 @@ sphinxcontrib-htmlhelp==1.0.3 sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-log-cabinet==1.0.1 - # via -r docs.in + # via -r requirements/docs.in sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.4 @@ -130,7 +130,7 @@ toml==0.10.2 # pytest # tox tox==3.23.1 - # via -r dev.in + # via -r requirements/dev.in typed-ast==1.4.3 # via mypy typing-extensions==3.10.0.0 diff --git a/requirements/docs.txt b/requirements/docs.txt index f1ee1f27..e59cd0d4 100644 --- a/requirements/docs.txt +++ b/requirements/docs.txt @@ -29,7 +29,7 @@ packaging==20.9 # pallets-sphinx-themes # sphinx pallets-sphinx-themes==2.0.1 - # via -r docs.in + # via -r requirements/docs.in pygments==2.9.0 # via # sphinx @@ -42,17 +42,17 @@ requests==2.25.1 # via sphinx snowballstemmer==2.1.0 # via sphinx -sphinx-issues==1.2.0 - # via -r docs.in -sphinx-tabs==3.0.0 - # via -r docs.in sphinx==4.0.2 # via - # -r docs.in + # -r requirements/docs.in # pallets-sphinx-themes # sphinx-issues # sphinx-tabs # sphinxcontrib-log-cabinet +sphinx-issues==1.2.0 + # via -r requirements/docs.in +sphinx-tabs==3.1.0 + # via -r requirements/docs.in sphinxcontrib-applehelp==1.0.2 # via sphinx sphinxcontrib-devhelp==1.0.2 @@ -62,7 +62,7 @@ sphinxcontrib-htmlhelp==1.0.3 sphinxcontrib-jsmath==1.0.1 # via sphinx sphinxcontrib-log-cabinet==1.0.1 - # via -r docs.in + # via -r requirements/docs.in sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.4 From d0f19f790520293c2c40207d492695e582347b1a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 10:05:36 +0000 Subject: [PATCH 016/109] Bump asgiref from 3.3.4 to 3.4.0 Bumps [asgiref](https://github.com/django/asgiref) from 3.3.4 to 3.4.0. - [Release notes](https://github.com/django/asgiref/releases) - [Changelog](https://github.com/django/asgiref/blob/main/CHANGELOG.txt) - [Commits](https://github.com/django/asgiref/commits) --- updated-dependencies: - dependency-name: asgiref dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements/dev.txt | 2 +- requirements/tests.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index 4603468a..a8908c6d 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -8,7 +8,7 @@ alabaster==0.7.12 # via sphinx appdirs==1.4.4 # via virtualenv -asgiref==3.3.4 +asgiref==3.4.0 # via -r requirements/tests.in attrs==21.2.0 # via pytest diff --git a/requirements/tests.txt b/requirements/tests.txt index deb93d62..600ad93a 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -4,7 +4,7 @@ # # pip-compile requirements/tests.in # -asgiref==3.3.4 +asgiref==3.4.0 # via -r requirements/tests.in attrs==21.2.0 # via pytest From ae53c32048dbef4ce1aaf9ecb86925e507118a38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 10:06:46 +0000 Subject: [PATCH 017/109] Bump pip-tools from 6.1.0 to 6.2.0 Bumps [pip-tools](https://github.com/jazzband/pip-tools) from 6.1.0 to 6.2.0. - [Release notes](https://github.com/jazzband/pip-tools/releases) - [Changelog](https://github.com/jazzband/pip-tools/blob/master/CHANGELOG.md) - [Commits](https://github.com/jazzband/pip-tools/compare/6.1.0...6.2.0) --- updated-dependencies: - dependency-name: pip-tools dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements/dev.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index a8908c6d..85ee227c 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -64,7 +64,7 @@ pallets-sphinx-themes==2.0.1 # via -r requirements/docs.in pep517==0.10.0 # via pip-tools -pip-tools==6.1.0 +pip-tools==6.2.0 # via -r requirements/dev.in pluggy==0.13.1 # via @@ -141,6 +141,8 @@ virtualenv==20.4.6 # via # pre-commit # tox +wheel==0.36.2 + # via pip-tools # The following packages are considered to be unsafe in a requirements file: # pip From c9796f85c787b5d01417a50ba25354be3b620afc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 10:06:57 +0000 Subject: [PATCH 018/109] Bump python-dotenv from 0.17.1 to 0.18.0 Bumps [python-dotenv](https://github.com/theskumar/python-dotenv) from 0.17.1 to 0.18.0. - [Release notes](https://github.com/theskumar/python-dotenv/releases) - [Changelog](https://github.com/theskumar/python-dotenv/blob/master/CHANGELOG.md) - [Commits](https://github.com/theskumar/python-dotenv/compare/v0.17.1...v0.18.0) --- updated-dependencies: - dependency-name: python-dotenv dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements/dev.txt | 2 +- requirements/tests.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index a8908c6d..3c510d15 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -84,7 +84,7 @@ pyparsing==2.4.7 # via packaging pytest==6.2.4 # via -r requirements/tests.in -python-dotenv==0.17.1 +python-dotenv==0.18.0 # via -r requirements/tests.in pytz==2021.1 # via babel diff --git a/requirements/tests.txt b/requirements/tests.txt index 600ad93a..6bfc63fa 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -24,7 +24,7 @@ pyparsing==2.4.7 # via packaging pytest==6.2.4 # via -r requirements/tests.in -python-dotenv==0.17.1 +python-dotenv==0.18.0 # via -r requirements/tests.in toml==0.10.2 # via pytest From 72078148c017e2e3e6d6b6716aa8f9f16e0bf2f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 10:07:58 +0000 Subject: [PATCH 019/109] Bump mypy from 0.812 to 0.910 Bumps [mypy](https://github.com/python/mypy) from 0.812 to 0.910. - [Release notes](https://github.com/python/mypy/releases) - [Commits](https://github.com/python/mypy/compare/v0.812...v0.910) --- updated-dependencies: - dependency-name: mypy dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- requirements/dev.txt | 5 ++--- requirements/typing.txt | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/requirements/dev.txt b/requirements/dev.txt index a8908c6d..d761ff6d 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -48,7 +48,7 @@ jinja2==3.0.1 # via sphinx markupsafe==2.0.1 # via jinja2 -mypy==0.812 +mypy==0.910 # via -r requirements/typing.in mypy-extensions==0.4.3 # via mypy @@ -125,14 +125,13 @@ sphinxcontrib-serializinghtml==1.1.4 # via sphinx toml==0.10.2 # via + # mypy # pep517 # pre-commit # pytest # tox tox==3.23.1 # via -r requirements/dev.in -typed-ast==1.4.3 - # via mypy typing-extensions==3.10.0.0 # via mypy urllib3==1.26.5 diff --git a/requirements/typing.txt b/requirements/typing.txt index 0e342aaa..fa04c8ad 100644 --- a/requirements/typing.txt +++ b/requirements/typing.txt @@ -4,11 +4,11 @@ # # pip-compile requirements/typing.in # +mypy==0.910 + # via -r requirements/typing.in mypy-extensions==0.4.3 # via mypy -mypy==0.812 - # via -r requirements/typing.in -typed-ast==1.4.3 +toml==0.10.2 # via mypy typing-extensions==3.10.0.0 # via mypy From 9fa8b0f7ad64c0cb3729978f88b5ebdc296ba750 Mon Sep 17 00:00:00 2001 From: Grey Li Date: Thu, 1 Jul 2021 18:43:35 +0800 Subject: [PATCH 020/109] Fix typing import issues --- setup.cfg | 3 +++ tox.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/setup.cfg b/setup.cfg index 77616866..e25c1e27 100644 --- a/setup.cfg +++ b/setup.cfg @@ -112,3 +112,6 @@ ignore_missing_imports = True [mypy-dotenv.*] ignore_missing_imports = True + +[mypy-cryptography.*] +ignore_missing_imports = True diff --git a/tox.ini b/tox.ini index c24ec0ff..66d1658c 100644 --- a/tox.ini +++ b/tox.ini @@ -24,7 +24,7 @@ commands = pre-commit run --all-files --show-diff-on-failure [testenv:typing] deps = -r requirements/typing.txt -commands = mypy +commands = mypy --install-types --non-interactive [testenv:docs] deps = -r requirements/docs.txt From f9ccca97e476a9ffc1fcdf081f9f083a119c5ce2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 5 Jul 2021 22:11:00 +0000 Subject: [PATCH 021/109] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/asottile/pyupgrade: v2.15.0 → v2.20.0](https://github.com/asottile/pyupgrade/compare/v2.15.0...v2.20.0) - [github.com/psf/black: 21.5b1 → 21.6b0](https://github.com/psf/black/compare/21.5b1...21.6b0) - [github.com/pre-commit/pre-commit-hooks: v3.4.0 → v4.0.1](https://github.com/pre-commit/pre-commit-hooks/compare/v3.4.0...v4.0.1) --- .pre-commit-config.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d75f3c31..a23c48af 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ ci: autoupdate_schedule: monthly repos: - repo: https://github.com/asottile/pyupgrade - rev: v2.15.0 + rev: v2.20.0 hooks: - id: pyupgrade args: ["--py36-plus"] @@ -14,7 +14,7 @@ repos: files: "^(?!examples/)" args: ["--application-directories", "src"] - repo: https://github.com/psf/black - rev: 21.5b1 + rev: 21.6b0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 @@ -25,7 +25,7 @@ repos: - flake8-bugbear - flake8-implicit-str-concat - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.4.0 + rev: v4.0.1 hooks: - id: fix-byte-order-marker - id: trailing-whitespace From 6e1b72096d5ae1e2cc4d8592ff8271b62548d9cf Mon Sep 17 00:00:00 2001 From: Adrian Moennich Date: Tue, 6 Jul 2021 22:05:31 +0200 Subject: [PATCH 022/109] Fix typo in docs --- src/flask/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flask/app.py b/src/flask/app.py index 22cc9abc..8c3c39d4 100644 --- a/src/flask/app.py +++ b/src/flask/app.py @@ -1306,7 +1306,7 @@ class Flask(Scaffold): .. versionchanged:: 1.0 Exceptions are looked up by code *and* by MRO, so - ``HTTPExcpetion`` subclasses can be handled with a catch-all + ``HTTPException`` subclasses can be handled with a catch-all handler for the base ``HTTPException``. .. versionadded:: 0.3 From 922e91b278c19bee1154ea32a7c0c99f87d4d9b6 Mon Sep 17 00:00:00 2001 From: Frank Yu Date: Wed, 7 Jul 2021 15:16:29 +0800 Subject: [PATCH 023/109] Omit the type attribute of script tag --- docs/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api.rst b/docs/api.rst index e6862878..09fc71a9 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -256,7 +256,7 @@ the filter to render data inside `` From 29c09a92c45bc0120331dd22f7079f9161d72ab7 Mon Sep 17 00:00:00 2001 From: Frank Yu Date: Wed, 7 Jul 2021 15:18:04 +0800 Subject: [PATCH 024/109] Omit the type attribute of script tag --- docs/patterns/jquery.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/patterns/jquery.rst b/docs/patterns/jquery.rst index fafbdf18..0a75bb71 100644 --- a/docs/patterns/jquery.rst +++ b/docs/patterns/jquery.rst @@ -23,8 +23,7 @@ to add a script statement to the bottom of your ```` to load jQuery: .. sourcecode:: html - + Another method is using Google's `AJAX Libraries API `_ to load jQuery: @@ -59,7 +58,7 @@ like this: .. sourcecode:: html+jinja - @@ -109,7 +108,7 @@ usually a better idea to have that in a separate script file: .. sourcecode:: html -