Skip to content

Commit 9ac6894

Browse files
authored
Merge pull request #792 from kenfj/fix-streamingresponse-issue
Fix StreamingResponse handling in _resp
2 parents c9d0a4b + 71b3745 commit 9ac6894

File tree

2 files changed

+52
-6
lines changed

2 files changed

+52
-6
lines changed

fasthtml/core.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,8 +448,8 @@ def _resp(req, resp, cls=empty, status_code=200):
448448
if cls in (Any,FT): cls=empty
449449
if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)
450450
resp,kw = _part_resp(req, resp)
451-
if cls is not empty: return cls(resp, status_code=status_code, **kw)
452451
if isinstance(resp, Response): return resp
452+
if cls is not empty: return cls(resp, status_code=status_code, **kw)
453453
if _is_ft_resp(resp):
454454
cts = _xt_cts(req, resp)
455455
return HTMLResponse(cts, status_code=status_code, **kw)

nbs/api/00_core.ipynb

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@
130130
{
131131
"data": {
132132
"text/plain": [
133-
"datetime.datetime(2025, 11, 19, 14, 0)"
133+
"datetime.datetime(2025, 11, 6, 14, 0)"
134134
]
135135
},
136136
"execution_count": null,
@@ -644,6 +644,14 @@
644644
"id": "4b36f60b",
645645
"metadata": {},
646646
"outputs": [
647+
{
648+
"name": "stderr",
649+
"output_type": "stream",
650+
"text": [
651+
"/var/folders/mp/wqhpw2456_79dcf12s7696m80000gn/T/ipykernel_76187/1644855005.py:8: DeprecationWarning: 'asyncio.iscoroutinefunction' is deprecated and slated for removal in Python 3.16; use inspect.iscoroutinefunction() instead\n",
652+
" if ctor: return await ctor(data, req) if asyncio.iscoroutinefunction(ctor) else ctor(data, req)\n"
653+
]
654+
},
647655
{
648656
"data": {
649657
"text/plain": [
@@ -1365,8 +1373,8 @@
13651373
" if cls in (Any,FT): cls=empty\n",
13661374
" if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)\n",
13671375
" resp,kw = _part_resp(req, resp)\n",
1368-
" if cls is not empty: return cls(resp, status_code=status_code, **kw)\n",
13691376
" if isinstance(resp, Response): return resp\n",
1377+
" if cls is not empty: return cls(resp, status_code=status_code, **kw)\n",
13701378
" if _is_ft_resp(resp):\n",
13711379
" cts = _xt_cts(req, resp)\n",
13721380
" return HTMLResponse(cts, status_code=status_code, **kw)\n",
@@ -1378,6 +1386,44 @@
13781386
" return cls(resp, status_code=status_code, **kw)"
13791387
]
13801388
},
1389+
{
1390+
"cell_type": "code",
1391+
"execution_count": null,
1392+
"id": "e2e4a9c2",
1393+
"metadata": {},
1394+
"outputs": [],
1395+
"source": [
1396+
"# Test for StreamingResponse behavior\n",
1397+
"# Before the fix, the following error occurs:\n",
1398+
"# TypeError: 'StreamingResponse' object is not iterable\n",
1399+
"import asyncio\n",
1400+
"from fasthtml.common import fast_app\n",
1401+
"from starlette.applications import Starlette\n",
1402+
"from starlette.responses import StreamingResponse\n",
1403+
"from starlette.testclient import TestClient\n",
1404+
"from starlette.routing import Route\n",
1405+
"\n",
1406+
"def simple_message_generator():\n",
1407+
" async def gen():\n",
1408+
" for i in range(3):\n",
1409+
" yield f\"data: message {i}\\n\\n\"\n",
1410+
" await asyncio.sleep(0.01)\n",
1411+
" return gen()\n",
1412+
"\n",
1413+
"app, rt = fast_app()\n",
1414+
"\n",
1415+
"@rt(\"/sse/notify\", methods=[\"GET\"])\n",
1416+
"async def get_sse_notify(req) -> StreamingResponse:\n",
1417+
" return EventStream(simple_message_generator())\n",
1418+
"\n",
1419+
"client = TestClient(app)\n",
1420+
"response = client.get('/sse/notify')\n",
1421+
"\n",
1422+
"assert response.status_code == 200\n",
1423+
"assert response.headers['content-type'].startswith('text/event-stream')\n",
1424+
"assert \"message\" in response.text"
1425+
]
1426+
},
13811427
{
13821428
"cell_type": "code",
13831429
"execution_count": null,
@@ -2887,13 +2933,13 @@
28872933
"name": "stdout",
28882934
"output_type": "stream",
28892935
"text": [
2890-
"Set to 2025-11-19 08:56:35.141231\n"
2936+
"Set to 2025-11-06 21:42:16.392974\n"
28912937
]
28922938
},
28932939
{
28942940
"data": {
28952941
"text/plain": [
2896-
"'Session time: 2025-11-19 08:56:35.141231'"
2942+
"'Session time: 2025-11-06 21:42:16.392974'"
28972943
]
28982944
},
28992945
"execution_count": null,
@@ -3510,7 +3556,7 @@
35103556
{
35113557
"data": {
35123558
"text/plain": [
3513-
"'Cookie was set at time 08:56:36.257555'"
3559+
"'Cookie was set at time 21:42:17.129483'"
35143560
]
35153561
},
35163562
"execution_count": null,

0 commit comments

Comments
 (0)