My preference would be to provide an alternative, something like calling app.asgi() instead of app.run() for functionality that implements the requirements.
So I’m not sure how feasible it is to shim the websockets support in if you wanted to take that approach. You also lose a chunk of benefits, since you’re only dealing with ASGI at the outermost layer (So you can use ASGI servers and Middleware, but can’t submount other ASGI applications.)
Shimming would lose a bit of performance in the ASGI case since you’re crossing two different kinds of interface boundaries, and have a little bit of work to do as a result of that. It would also be a higher complexity, since you’ve got two ways around, where properly engineering Sanic around an ASGI interface throughout would cut a few bits out instead.
the same way people don’t run synchronous frameworks under WSGI.
I’m not sure there are any significant Python sync frameworks that aren’t WSGI based. A few have in-built devservers, but they still use the WSGI interface under the hood.
There’s not too much going on in
Request.__init__
. What exactly did you have in mind? Have a couple quick lines of code to help me understand?
Sure. Given that the ASGI interface passes a scope
dictionary in, a nice approach is to ensure that Request(scope=scope)
as the standard way to instantiate a request instance. (Perhaps you also accept keyword arguments to support eg. Request(url=..., method=..., headers=...)
, but that’s not what you want to use internally.)
keep the same app.run()
That’s absolutely fine. I’m not personally particularly interested in adapting the Sanic sever part to deal with that, but if someone else took on that part on then great. (Or deal with it by adding a dependency.) In either case it’d likely make sense to deal with the framework adaptations first, to demonstrate support with uvicorn & pals, to test performance, and to thrash out what-if-any API changes are/aren’t required.
Just to give a bit more of a push to the motivations here, it’s not just about being able to run sanic
with uvicorn, hypercorn, or daphne. It’s also about:
- Shared ASGI middleware. (Eg. You be able to use Starlette’s
CORSMiddleware
,SessionMiddleware
,GZipMiddleware
,TrustedHostMiddleware
,HTTPSRedirectMiddleware
,ExceptionMiddleware
,DebugMiddleware
etc.) - Shared mountable ASGI applications (Eg. Use Starlette’s
StaticFiles
,GraphQLApp
, class-basedHTTPEndpoint
/WebSocketEndpoint
implementations etc…) - Interchangeable response classes (Eg. use Sanic responses with Starlette and vice-versa. We’ve both got all the basics covered here, but there’s other things like content-negotiated response classes that’d be useful in either case.)
- Properly managed background tasks. (Eg. server restarts don’t finalize until background tasks have run to completion. Server is able to determine number of concurrent background tasks, etc.)
- Support for WebSockets, Server Sent Events, HTTP/2 server push.
- More robust HTTP and WebSocket implementations, due to proper interface separation.