Skip to content

Conversation

@davidism
Copy link
Member

@davidism davidism commented Sep 12, 2025

Merges the RequestContext class into the AppContext class. closes #5639

A lot of the size of this PR is rewriting or cleaning up docs related to the contexts. See ctx.py for 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_request and teardown_appcontext still both exist, app.app_context and app.test_request_context, etc. All the same global proxies, current_app, g, request, and session still 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_app functions would only run once the with block exited rather than when the request exited. Along with using with client around 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, g was part of the app context, not the request context. Data could be set on g ahead of the request, because a new app context wouldn't be pushed. This was never documented, I don't know where I saw it.

# do not do this, for example only
with app.app_context():
    g.user = test_user
    r = client.get("/secret")

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 g beforehand, the signal docs show using the appcontext_pushed signal to modify the current context's g once 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_context was already not copying g. I thought about changing this, but concluded that it was a good thing, because g is often used to store connections/caches that are not concurrent safe, such as Flask-SQLAlchemy's db.session.

@davidism davidism added this to the 3.2.0 milestone Sep 12, 2025
@davidism
Copy link
Member Author

Would be great if some people could test their apps with this branch. I'll plan to merge it a week from now.

@ThiefMaster
Copy link
Member

after uv pip install 'git+https://github.com/pallets/flask@merge-contexts' on indico master:

  • no errors at import time
  • no errors when running the repl w/ all the indico stuff imported (indico shell)
  • no errors accessing it via web (custom wrapper running the flask dev server)
  • all tests still passing

@davidism
Copy link
Member Author

Thanks to those who tested and left a 🚀 or commented on Mastodon. Having a big app like Indico pass unchanged is a good sign as well. Time to merge this.

@davidism davidism merged commit adf3636 into main Sep 19, 2025
12 checks passed
@davidism davidism deleted the merge-contexts branch September 19, 2025 23:45
ryantqiu pushed a commit to snorkel-marlin-repos/flask_7d7453a5 that referenced this pull request Oct 1, 2025
Original PR #5812 by davidism
Original: pallets/flask#5812
ryantqiu added a commit to snorkel-marlin-repos/flask_7d7453a5 that referenced this pull request Oct 1, 2025
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Oct 4, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

merge app and request contexts into a single context

3 participants