Skip to content
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

Trio support. #811

Closed
tomchristie opened this issue Jan 28, 2020 · 9 comments · Fixed by #1157
Closed

Trio support. #811

tomchristie opened this issue Jan 28, 2020 · 9 comments · Fixed by #1157
Labels
feature New feature or request

Comments

@tomchristie
Copy link
Member

Via https://gitter.im/python-trio/general?at=5e2fe9b940da694c5edc8d70

It'd be nice to have Starlette support both Trio and Asyncio.

Currently it's an asyncio-only framework, but there's actually not many places where we're tied to asyncio, with the exception of a bunch of "if this callable is a plain function then call into with with run_in_threadpool, otherwise await it.".

I think the other places are:

  • The WSGI middleware (optional). Currently has an asyncio-based implementation.
  • The BaseHTTPMiddleware class (optional), that provides a request/response middleware interface to develop against, rather than directly writing against ASGI. Again, currently has an asyncio-based implemention.
  • One weird part of the request model, .is_disconnected - that I think is structured as an anti-pattern and probably needs rethinking.
  • The graphene-based GraphQL async executor, which probably ought to come out of the core package anyways.
  • The existing TestClient, which we oughta replace with httpx now anyways, which does have trio+asyncio.

Short: Tweaking our run_in_threadpool function to use sniffio and then either call trio's threadpooling or asyncio's threadpooling would be sufficient as a starting point to start using Starlette with Trio.

@tomchristie tomchristie added the feature New feature or request label Jan 28, 2020
@gdhameeja
Copy link

I'm taking this up.

@jtrakk
Copy link

jtrakk commented Feb 28, 2020

@gdhameeja Can you share a link to your repo so we can follow along?

@tammoippen
Copy link

tammoippen commented May 4, 2020

Also, FileResponse uses aiofiles, which is asyncio based. Here the trio i/o could be used?

Edit: And StaticFiles.

@parity3
Copy link

parity3 commented Jun 15, 2020

I figured these possible alternatives / POC / intermediate steps are worth mentioning here.

@pquentin
Copy link
Contributor

For what it's worth, here's an example of Uvicorn + Starlette + FastAPI running with trio-asyncio: python-trio/trio-asyncio#84

@uSpike
Copy link
Member

uSpike commented Mar 26, 2021

I'm taking this up.

@gdhameeja any updates? I'd like to take a stab at using anyio if nobody else is working on this.

@uSpike uSpike mentioned this issue Mar 26, 2021
3 tasks
@uSpike
Copy link
Member

uSpike commented Mar 26, 2021

I took an initial stab at using anyio in #1157

It was surprisingly easy but I'd like some feedback if anyone would be so kind. There's a few things left to do/fix. All done!

@espetro
Copy link

espetro commented Aug 17, 2021

Hi! Thanks for such an amazing work 🙌🏼 , I cannot wait to try trio with Starlette. How are we supposed to enable it? There's only documentation for TestClient.

@Sxderp
Copy link

Sxderp commented Aug 17, 2021

@espetro For a very simple web server. In this I use hypercorn (runs the server) + starlette (handles the processing). 90% of Starlette worked on trio before the anyio patch. There were just a few bits (error handling is one I can think of) that failed / cashed. You really don't have to do anything to "enable" trio. Your web server (in my case hypercorn) is doing most of the heavy lifting.

import trio
from hypercorn.config import Config
from hypercorn.trio import serve
from starlette.applications import Starlette
from starlette.responses import JSONResponse
from starlette.routing import Route

class IPC(Starlette):
    def __init__(self):
        super().__init__(routes=[Route('/index', self._index)])

    async def _index(self, request):
        return JSONResponse({'foo': 'bar'}, status_code=200)


async def bootstrap():
    hyper_config = Config.from_mapping({'bind': '127.0.0.1:56601'})
    async with trio.open_nursery() as nursery:
        nursery.start_soon(serve, IPC(), hyper_config)


if __name__ == '__main__':
    trio.run(bootstrap)

And then

$ curl http://127.0.0.1:56601/index
{"foo":"bar"}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants