encode / httpx

A next generation HTTP client for Python. 🦋
https://www.python-httpx.org/
BSD 3-Clause "New" or "Revised" License
13.26k stars 840 forks source link

ASGITransport does not stream responses. #2186

Open havardthom opened 2 years ago

havardthom commented 2 years ago

Current behaviour:

Expected behaviour:

# test_endless_sse.py
import pytest
import httpx
import asyncio

from fastapi import FastAPI
from sse_starlette.sse import EventSourceResponse

app = FastAPI()

@app.get("/endless_sse")
async def endless_sse():
    async def event_publisher():
        i = 0
        try:
            while True:
                i += 1
                yield dict(data=i)
                await asyncio.sleep(0.2)
        except asyncio.CancelledError as e:
            raise e

    return EventSourceResponse(event_publisher())

# This test should pass but it hangs forever and prints no output
@pytest.mark.asyncio
async def test_endless_sse():
    async with httpx.AsyncClient(app=app, base_url="http://test") as aclient:
        async with aclient.stream("GET", "/endless_sse") as response:
            async for line in response.aiter_lines():
                line_stripped = line.strip()
                print("line_stripped: ", line_stripped)
                if line_stripped == "data: 10":
                    break

if __name__ == "__main__":
    # Run: uvicorn test_endless_sse:app --reload

    # Check that we get output from the app running in uvicorn
    async def fetch_endless_sse():
        async with httpx.AsyncClient(base_url="http://127.0.0.1:8000") as aclient:
            async with aclient.stream("GET", "/endless_sse") as response:
                async for line in response.aiter_lines():
                    line_stripped = line.strip()
                    print("line_stripped: ", line_stripped)
                    if line_stripped == "data: 10":
                        break

    asyncio.run(fetch_endless_sse())
python 3.8.0

httpx==0.22.0
pytest==7.1.1
pytest-asyncio==0.18.3
fastapi==0.75.2
uvicorn==0.17.6
sse-starlette==0.10.3

Related: https://github.com/tiangolo/fastapi/issues/2006

tomchristie commented 2 years ago

You've identified this correctly in your comment here... https://github.com/encode/httpx/discussions/1787#discussioncomment-1537543

The issue is that the ASGITransport doesn't stream responses. I've retitled this issue to be more specific regarding what's needed to resolve this.

aditya-n-invcr commented 2 years ago

@tomchristie Is there any update on this one ? Or has it already been fixed ?

florimondmanca commented 2 years ago

As mentioned in havardthom's comment, I had a previous PR from a long time ago here which attempted to solve something that would resolve this: https://github.com/encode/httpx/pull/998

It's okay to start off that PR, adjusting anything that needs to be due to changes in HTTPX since then.

Kludex commented 2 years ago

If no one takes this until the end of the year, I will.

EDIT on 28 July 2023: I lied.

richardhundt commented 1 year ago

I've run into the same issue, and unfortunately @florimondmanca's branch didn't work for me (all requests hang, not just SSE streams). I used that as inspiration though, and am monkey patching the transport in my tests. Here's a gist: https://gist.github.com/richardhundt/17dfccb5c1e253f798999fc2b2417d7e

tomchristie commented 1 year ago

My suggestion would be that we document this as a known constraint.

If someone is invested in resolving it, then implementing it as a third party transport would be a good first step.

galah92 commented 2 months ago

I've got the same problem - FastAPI SSE endpoint I'd like to test. Is there a workaround for this?