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.
Following discussions for Flask we've decided to name blueprints based
on how they are registered. This allows for two different blueprints
to have the same self-name as long as they are registered in different
nested positions. This helps users choose better blueprint names.
TypeVar is needed to preserve function signatures. The type cast for
update_wrapper is needed because wapper_func can not use the full
signature that f does.
It is better to encourage users to utilise the app ensure_sync method
(or the newely added async_to_sync method) so that any extensions that
alter these methods take affect throughout the users code.
With the helper method users code fix parts of their code to the
asgiref async_to_sync ignoring any extension changes.
Firstly `run_sync` was a misleading name as it didn't run anything,
instead I think `async_to_sync` is much clearer as it converts a
coroutine function to a function. (Name stolen from asgiref).
Secondly trying to run the ensure_sync during registration made the
code more complex and brittle, e.g. the _flask_async_wrapper
usage. This was done to pay any setup costs during registration rather
than runtime, however this only saved a iscoroutne check. It allows
the weirdness of the Blueprint and Scaffold ensure_sync methods to be
removed.
Switching to runtime ensure_sync usage provides a method for
extensions to also support async, as now documented.
This was required with the previous implementation of Werkzeug's
locals which didn't persist across threads. However as the current
implementation uses ContextVars which do persist the context copying
is no longer required.
As long as popular libraries (e.g. Celery) require click 7, depending
on Click 8 in Flask makes it hard to test the latest version (and its
other dependencies) in existing applications.