Skip to content

Commit f0f0593

Browse files
committed
Fix StreamingResponse handling in _resp
1 parent 00e13f6 commit f0f0593

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
@@ -449,8 +449,8 @@ def _resp(req, resp, cls=empty, status_code=200):
449449
if cls in (Any,FT): cls=empty
450450
if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)
451451
resp,kw = _part_resp(req, resp)
452-
if cls is not empty: return cls(resp, status_code=status_code, **kw)
453452
if isinstance(resp, Response): return resp
453+
if cls is not empty: return cls(resp, status_code=status_code, **kw)
454454
if _is_ft_resp(resp):
455455
cts = _xt_cts(req, resp)
456456
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
@@ -131,7 +131,7 @@
131131
{
132132
"data": {
133133
"text/plain": [
134-
"datetime.datetime(2025, 10, 27, 14, 0)"
134+
"datetime.datetime(2025, 11, 6, 14, 0)"
135135
]
136136
},
137137
"execution_count": null,
@@ -645,6 +645,14 @@
645645
"id": "4b36f60b",
646646
"metadata": {},
647647
"outputs": [
648+
{
649+
"name": "stderr",
650+
"output_type": "stream",
651+
"text": [
652+
"/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",
653+
" if ctor: return await ctor(data, req) if asyncio.iscoroutinefunction(ctor) else ctor(data, req)\n"
654+
]
655+
},
648656
{
649657
"data": {
650658
"text/plain": [
@@ -1366,8 +1374,8 @@
13661374
" if cls in (Any,FT): cls=empty\n",
13671375
" if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)\n",
13681376
" resp,kw = _part_resp(req, resp)\n",
1369-
" if cls is not empty: return cls(resp, status_code=status_code, **kw)\n",
13701377
" if isinstance(resp, Response): return resp\n",
1378+
" if cls is not empty: return cls(resp, status_code=status_code, **kw)\n",
13711379
" if _is_ft_resp(resp):\n",
13721380
" cts = _xt_cts(req, resp)\n",
13731381
" return HTMLResponse(cts, status_code=status_code, **kw)\n",
@@ -1379,6 +1387,44 @@
13791387
" return cls(resp, status_code=status_code, **kw)"
13801388
]
13811389
},
1390+
{
1391+
"cell_type": "code",
1392+
"execution_count": null,
1393+
"id": "e2e4a9c2",
1394+
"metadata": {},
1395+
"outputs": [],
1396+
"source": [
1397+
"# Test for StreamingResponse behavior\n",
1398+
"# Before the fix, the following error occurs:\n",
1399+
"# TypeError: 'StreamingResponse' object is not iterable\n",
1400+
"import asyncio\n",
1401+
"from fasthtml.common import fast_app\n",
1402+
"from starlette.applications import Starlette\n",
1403+
"from starlette.responses import StreamingResponse\n",
1404+
"from starlette.testclient import TestClient\n",
1405+
"from starlette.routing import Route\n",
1406+
"\n",
1407+
"def simple_message_generator():\n",
1408+
" async def gen():\n",
1409+
" for i in range(3):\n",
1410+
" yield f\"data: message {i}\\n\\n\"\n",
1411+
" await asyncio.sleep(0.01)\n",
1412+
" return gen()\n",
1413+
"\n",
1414+
"app, rt = fast_app()\n",
1415+
"\n",
1416+
"@rt(\"/sse/notify\", methods=[\"GET\"])\n",
1417+
"async def get_sse_notify(req) -> StreamingResponse:\n",
1418+
" return EventStream(simple_message_generator())\n",
1419+
"\n",
1420+
"client = TestClient(app)\n",
1421+
"response = client.get('/sse/notify')\n",
1422+
"\n",
1423+
"assert response.status_code == 200\n",
1424+
"assert response.headers['content-type'].startswith('text/event-stream')\n",
1425+
"assert \"message\" in response.text"
1426+
]
1427+
},
13821428
{
13831429
"cell_type": "code",
13841430
"execution_count": null,
@@ -2888,13 +2934,13 @@
28882934
"name": "stdout",
28892935
"output_type": "stream",
28902936
"text": [
2891-
"Set to 2025-10-27 07:27:07.025956\n"
2937+
"Set to 2025-11-06 21:42:16.392974\n"
28922938
]
28932939
},
28942940
{
28952941
"data": {
28962942
"text/plain": [
2897-
"'Session time: 2025-10-27 07:27:07.025956'"
2943+
"'Session time: 2025-11-06 21:42:16.392974'"
28982944
]
28992945
},
29002946
"execution_count": null,
@@ -3511,7 +3557,7 @@
35113557
{
35123558
"data": {
35133559
"text/plain": [
3514-
"'Cookie was set at time 07:28:31.264910'"
3560+
"'Cookie was set at time 21:42:17.129483'"
35153561
]
35163562
},
35173563
"execution_count": null,

0 commit comments

Comments
 (0)