diff --git a/src/aiopenapi3/request.py b/src/aiopenapi3/request.py index 5e5395b3..de1633f5 100644 --- a/src/aiopenapi3/request.py +++ b/src/aiopenapi3/request.py @@ -344,6 +344,26 @@ def iter_json(response: httpx.Response) -> Iterator["JSON"]: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events """ + def iter_json(response: httpx.Response) -> Iterator["JSON"]: + for chunk in response.iter_text(): + data_ = "" + for line in chunk.splitlines(keepends=True): + data_ += line + if not data_.endswith(("\r\r", "\n\n", "\r\n\r\n")): + continue + + v = dict() + for l in data_.splitlines(keepends=False): + if l == "": + continue + cmd, _, value = l.partition(":") + if cmd not in ("event", "data", "id", "retry", ""): + # ignore + continue + v[cmd or "comment"] = value.lstrip() + data_ = "" + yield v + elif False: import ijson class ReadEventStream: diff --git a/tests/sequential_test.py b/tests/sequential_test.py index 9bdc50d3..d396e8fb 100644 --- a/tests/sequential_test.py +++ b/tests/sequential_test.py @@ -109,4 +109,3 @@ async def test_sse(server, client): async with req.sequence() as sequence: async for obj in sequence: print(obj) - await asyncio.sleep(1.1) diff --git a/tests/v32_test.py b/tests/v32_test.py index 6e283db0..438d4047 100644 --- a/tests/v32_test.py +++ b/tests/v32_test.py @@ -32,11 +32,12 @@ async def test_MediaType(httpx_mock, with_schema_itemSchema): import pydantic api = OpenAPI("https://example.org/api/", with_schema_itemSchema, session_factory=httpx.AsyncClient) - ServerSentEvent: pydantic.BaseModel = api.components.schemas["ServerSentEvent"].get_type() records = with_schema_itemSchema["components"]["examples"]["LogJSONPerLine"]["value"].strip("\n").split("\n") + + ServerSentEvent: pydantic.BaseModel = api.components.schemas["ServerSentEvent"].get_type() t = pydantic.TypeAdapter(list[ServerSentEvent]) - ct = "\n\n".join(f"data: {i}" for i in records * 16) + ct = "\n\n".join(f"data: {i}\n: {idx}" for idx, i in enumerate(records * 16)) httpx_mock.add_response( url="https://example.org/api/json_seq", @@ -95,15 +96,46 @@ def test_MediaType_itemSchema_sync(httpx_mock, with_schema_itemSchema): records = with_schema_itemSchema["components"]["examples"]["LogJSONPerLine"]["value"].strip("\n").split("\n") + ServerSentEvent: pydantic.BaseModel = api.components.schemas["ServerSentEvent"].get_type() + t = pydantic.TypeAdapter(list[ServerSentEvent]) + ct = "\n\n".join(f"data: {i}\n: {idx}" for idx, i in enumerate(records * 16)) + httpx_mock.add_response( url="https://example.org/api/json_seq", headers={"Content-Type": "application/json-seq"}, stream=IteratorStream([b"\x1e" + i.encode() + b"\n" for i in (records * 16)]), ) + httpx_mock.add_response( + url="https://example.org/api/jsonl", + headers={"Content-Type": "application/jsonl"}, + stream=IteratorStream([i.encode() + b"\n" for i in (records * 16)]), + ) + httpx_mock.add_response( + url="https://example.org/api/ndjson", + headers={"Content-Type": "application/x-ndjson"}, + stream=IteratorStream([i.encode() + b"\n" for i in (records * 16)]), + ) + httpx_mock.add_response( + url="https://example.org/api/text_events", headers={"Content-Type": "text/event-stream"}, content=ct + ) req = api.createRequest("json_seq") with req.sequence() as sequence: - print(sequence.headers) + for obj in sequence: + print(obj) + + req = api.createRequest("jsonl") + with req.sequence() as sequence: + for obj in sequence: + print(obj) + + req = api.createRequest("ndjson") + with req.sequence() as sequence: + for obj in sequence: + print(obj) + + req = api.createRequest("text_events") + with req.sequence() as sequence: for obj in sequence: print(obj)