dash
dash copied to clipboard
[Feature Request] FastAPI / other ASGI support
Hello!
We love Dash, it's been perfect for our team of Python developers who want to provide rich web frontends.
We're coming up against the issue that it's difficult to host alongside our other web services though, primarily because we use FastAPI. FastAPI is the most popular of the ASGI frontends but by no means the only one, if a solution could be found to support ASGI as well as WSGI, I think the other webservers could just slot in as well.
I've read up on various topics where this is mentioned, and aside from the non-trivial work to make it generic, it seems like the major blocker is Python 2.7 support, and Python 3.6 needed for async/await. I have every sympathy with having to support Enterprise Python, and I'm sure you're well aware of this, but Python 2.7 has been end of life for 15 months, and 3.5 has been end of life for six months.
Is there a roadmap for Dash 2.0? Would that be the time to support multiple backends and draw a line in the sand on versions?
References
https://community.plotly.com/t/websockets-devices-performance-gains/39669 https://github.com/plotly/dash/issues/1559
We are indeed working on a Dash 2.0 right now, but we're not quite ready to make the plans public yet - stay tuned, we'll be ready to share sometime this spring 🌸
But I'm happy to say we will drop Py2 support with Dash 2.0, and I believe Py3.6 is a reasonable new minimum. According to https://pypistats.org/packages/dash we still have a couple percent of users installing on 3.5 (and another couple percent on 2.7 🙈 ) but hopefully this change will help encourage them to upgrade!
So if you're interested in contributing a feature that requires Py3.6, in a couple of months we'll happily accept it into the core dash repo 😄
Thanks!
Do you think that there would be appetite for a switchable backend at that point, instead of just Flask?
As long as it's done in a way that's backward compatible for folks using the Flask server and interfacing directly with it via app.server
, I think it should be fine to generalize to other back ends.
I'm potentially interested in contributing/testing ASGI support. (I'm using Starlette/Uvicorn.)
Hello, I'm just circling back to this to ask if there is more clarity on Dash 2.0. I can see the announcements have been made, was it decided what versions of Python will be supported? Python 3.6 is EoL at the end of the year, so I wonder if even making 3.7 the minimum is worth considering, especially if the release will be in 2022.
@alexcjohnson it looks like Python 3.6 is now the minimum. Could this change now potentially go ahead?
Yes, Py3.6+ since Dash 2.0, so this is certainly a possibility! ASGI support isn't something that Plotly devs are planning to work on in the near future, but if you're up for creating a PR we'd be delighted to help bring it to completion.
Quart
already does most of the heavy lifting of masquerading as a Flask (via patching, to support Flask extensions). so switching Dash to use Quart was actually super trivial - mostly just wrapping async coroutines such as callbacks with ensure_sync
. And in particular, most remaining API incompatibilities were addressed in recent commits such as e.g. this and this.
And given that Quart is now officially a pallets/Flask team project, it really is a no-brainer to make a switch if you want to use Dash with ASGI backend.
Forgive me if this seems like a fairly naive comment, but what is the true difficulty in ASGI conversion? I've been experimenting with various asynchronous implementations like the monkey-patched version of Dash and it seems to me that a large portion of it falls on introducing async
/await
to the plethora of Dash functions especially where it relates to server request objects.
My main motivation for an asynchronous Dash implementation is that a monkey-patched version has fallen behind without constant updating. I submitted a PR to add duplicate callbacks to Async-Dash and pages are not currently supported except via another PR.
Would love for someone to comment on the overall complexity of the task - I'd love to get my feet dirty and contribute via PR. @alexcjohnson
@brendanillies
what is the true difficulty in ASGI conversion?
We need to keep flask as default server, the implementation would need to abstract everywhere we use flask.
I think it would be best to start with just allowing async callbacks, with flask 2.0 you can install flask[async]
to add async
routes. Could add the same dash[async]
and then check if the callback function is a co routine to await it if necessary. Basically can go from the change in the patched version to take in consideration the new code in dash._callback.py
. The function add_context
may need remain non-async if flask[async]
is not installed, it install asgiref
, maybe try import that if it work you can use the async one instead.
@brendanillies
what is the true difficulty in ASGI conversion?
We need to keep flask as default server, the implementation would need to abstract everywhere we use flask.
I think it would be best to start with just allowing async callbacks, with flask 2.0 you can install
flask[async]
to addasync
routes. Could add the samedash[async]
and then check if the callback function is a co routine to await it if necessary. Basically can go from the change in the patched version to take in consideration the new code indash._callback.py
. The functionadd_context
may need remain non-async ifflask[async]
is not installed, it installasgiref
, maybe try import that if it work you can use the async one instead.
Thanks for the info here. Unfortunately I've looked into this and with the number of user interactions and the necessity for plug and play websockets, Quart was the better option for me.
I will definitely be taking this away though and working with it a bit as I think there's flexibility to explore other servers. Maybe I'm underestimating the lift required, but if the need is there I'm happy to take it on. I'll report back with any questions I have!