merge app and request context #5812
Merged
+779
−1,007
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Merges the
RequestContextclass into theAppContextclass. closes #5639A lot of the size of this PR is rewriting or cleaning up docs related to the contexts. See
ctx.pyfor the bulk of the work, and even there it's pretty much no new code, mostly deduplication. The "request context" still exists, but what data is available on the context object is what distinguishes it from an "app context" now.How the user works with the context is pretty much unchanged. For example,
teardown_requestandteardown_appcontextstill both exist,app.app_contextandapp.test_request_context, etc. All the same global proxies,current_app,g,request, andsessionstill exist and are still available. in the same situations they were before.The difference is that we no longer have to track whether an app context is already pushed when pushing a request context. This was already sort of an artificial behavior, it was not something that would ever happen under intended/documented request or testing scenarios. Now, every request always sets the app, and the request if request data is given. This greatly simplifies the internal data, as we simply need to record the previous value of the context var to restore on pop.
Some code in app internals was changed to use the contextvar directly, which code was already doing. This probably gains some tiny bit of performance rather than going through the proxies. When we go ahead with #5229 and beyond, we'll be passing around the context objects directly and won't even need to use the contextvar.
There are a few implications for testing that may have used
with app.app_context()around a test client request. I've already highly discouraged this practice in issues over the years because it was already causing other issues. None of these patterns were in our docs.With the old behavior, an app context was not pushed if one was already pushed when pushing a request context. Therefore,
teardown_appfunctions would only run once thewithblock exited rather than when the request exited. Along with usingwith clientaround everything, this was already the source of occasional bug reports and questions. The docs also say that no assumptions should be made about how many times a teardown function will be called or what data will be set for them.Also,
gwas part of the app context, not the request context. Data could be set ongahead of the request, because a new app context wouldn't be pushed. This was never documented, I don't know where I saw it.It's not in Flask's docs or tests. The docs show making a request to login before making the request being tested, relying on the session to persist across requests. If you really wanted to set up
gbeforehand, the signal docs show using theappcontext_pushedsignal to modify the current context'sgonce it's created.A project may run into some failed tests when upgrading, if they were relying on this. However, the failure would indicate patterns that were already unsound and should be fixed, so I don't see this as a blocker.
Interestingly,
copy_current_request_contextwas already not copyingg. I thought about changing this, but concluded that it was a good thing, becausegis often used to store connections/caches that are not concurrent safe, such as Flask-SQLAlchemy'sdb.session.