-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Does werkzeug have plans to support ASGI? #1322
Comments
Yes, Werkzeug and Flask will eventually support ASGI. I do not have a timeline for this, although I would be happy to help review a PR if someone started one. However, I'm not going to be the one that implements it, I need help from the community. See the latest update below: #1322 (comment) |
I'm interested in working on this. I have some working but hacky ASGI support going on: werkzeug, flask. I'd like to understand more about any plans you may have before going any further. Things that occur to me already, beyond the fact that everything I've done there could be generally nicer:
Please let me know your thoughts. |
I guess the light touch approach will be just to reimplement the existing parser, but with async IO. It'd be cleaner if the two parser classes could share a common sans-IO implementation under the hood, but it might be more practical just to duplicate & slightly modify the existing implementation.
Context locals (for asyncio) exist in the 3.7 stdlib. https://docs.python.org/3.7/library/contextvars.html Does werkzeug use thread-locals? (I'm aware that Flask does)
I'd suggest not offering a synchronous interface for parsing form data. (Or for accessing the request body in any way), and instead just offer async APIs onto it. See Starlette's API for some examples here... https://github.com/encode/starlette#body |
Since Python 3.7 is out I wouldn't be opposed to having async features requiring Python 3.7 as long as no other code is affected by it. But if there's a backport that's as good as the native 3.7 solution - even better! Regarding async form data parsing... I guess something like |
Sure, or just make |
wouldn't that require rather ugly things like |
yes :( I'm not sure that's particularly avoidable, though. I don't think form = await request.form
form['foo'] is really any more or less ugly than await request.parse()
request.form['foo'] though that's obviously subject to taste. I guess we could also invent an "async dict" whose members are all async-ified instead, but without having seen one I'd imagine it would end up rather confusing. |
I'd suggest using function calls for I/O-performing operations, rather than properties.
Shrug - Don't do that. asyncio is necessarily more explicit about which parts of the codebase perform I/O, so I'd tend to split those out into separate lines. form = await request.form()
form['foo'] |
While I'm all for adding async support, we still can't break Python 2 and sync versions. One approach I heard about from @njsmith is to write everything as async, then use a tool similar to 2to3 to generate the sync version. Apparently it's being tried in urllib3, but I don't know enough about it. |
I wonder if we could add magic to the objects behind Or... |
That's the sort of approach that'd make sense to me, yeah. |
Regarding the form parser, I've made an attempt at sansio-ing it in #1330. |
There's also a streaming form parser implementation at https://github.com/andrew-d/python-multipart with 100% coverage. (I found one other but it wasn't obvious that it could be easily adapted into a "feed data, handle events" flow.)
|
I've also been thinking about best ways to present a sync and async compatible interface, since I also want that for Starlette (although going in the other direction to Werkzeug, for me it's about "I have an existing async interface, how do I now also present a sync one") For Starlette I think I'll probably push the actual parsing into an |
Off topic, but related to a popular ASGI and werkzeug case (I don't want to derail this issue, but don't want to create a duplicate issue without substance to add): If you're running https://github.com/django-extensions/django-extensions with (Werkzeug is used underneath the hood on Django with django-extensions and I spent a few hours figuring out why since I'm so used to developing with |
I use runserver_plus so that I can use https in development. |
This comment has been minimized.
This comment has been minimized.
On Jul 2, 2018 @davidism writes:
Just saw this from a while back – if anyone's interested in learning more, it looks like python-trio/hip#1 has a bunch of the details. Note the link to urllib3/urllib3#1323, which contains:
(Keep reading there if interested.) Nice to see this has apparently been continuing to work well, based on the steady progress being made at https://github.com/python-trio/urllib3/commits/bleach-spike. |
Small bump to make this issue back on the radar. With 3.5 reaching EOL this year, I think it's a good time to start thinking about async support? |
In the year and a half since this was posted, there hasn't been much activity to implement it. I don't personally have any experience or need for asyncio, and although I do like ASGI, it was never something that I was going to take on myself. In the mean time, @pgjones, author of Quart, has become more involved in Werkzeug. Quart now uses Werkzeug behind the scenes where possible, and we're continuing to develop that. There was some pushback from a Flask maintainer about going with ASGI, so Phil also created pallets/flask#3412 that at least allowed routing to You might ask, "Why can't Flask do what Django did?" I am not an expert on the internals of Django, but @andrewgodwin explained to me a while ago that Django has an "easier" (read: still very complicated) time of it due to how it originally adapted to WSGI, as opposed to the very WSGI-centric API that Werkzeug and Flask started with. Also, Django just gets a ton more full time attention and resources than Pallets does. So where does that leave this issue? If you want a Flask-compatible framework that uses Werkzeug, use Quart. Contribute to Quart (or Flask) to make them more API compatible where that's missing. If you want Werkzeug and Flask to support ASGI, you are going to need to step up. Start learning about ASGI. Start identifying the WSGI-specific and blocking parts of Werkzeug's API. Start thinking of abstractions we can make to enable implementations for both WSGI and ASGI. Then bring that research back to this discussion so we can start designing and writing PRs. |
Thanks for the Quart suggestion, I'd be very happy to accept contributions to it. I've tried to answer why I think Flask can't do what Django has done in this article. Ultimately I think pallets/flask#3412 is the best solution for Flask. In terms of Werkzeug I think that ASGI is possible, with some pain. A notable example of the pain is that many things in Werkzeug are WSGI callables (e.g. exceptions). With ASGI it isn't clear how this functionality could/should be used, so I'd prefer to remove it. My plan is to keep integrating Werkzeug into Quart adjusting Werkzeug towards ASGI (sans-io) as I go (as much as can be accepted) - my only obstacle is a lack of time. |
Various bits of Werkzeug, such as the At this point I'm going to close this issue. It hasn't really generated any outside contributions, and the answer is clearly "yes, we plan to support ASGI" and "yes, Quart uses Werkzeug and is ASGI". |
Werkzeug offers many useful methods, it would be much easier if it supported ASGI than if we started from scratch.
The text was updated successfully, but these errors were encountered: