Skip to content

Commit 170fb7e

Browse files
committed
fixes #307
1 parent fceea61 commit 170fb7e

File tree

13 files changed

+103
-147
lines changed

13 files changed

+103
-147
lines changed

demo/main.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ def render(item:'Todo'):
1212

1313
@rt("/")
1414
async def get(request):
15-
new_frm = Form(Group(Input(name='title', placeholder='Title'),
16-
Button('Add')), hx_post='/', target_id='todo-list', hx_swap='beforeend')
15+
new_frm = Form(hx_post='/', target_id='todo-list', hx_swap='beforeend')(
16+
Group(
17+
Input(name='title', placeholder='Title'),
18+
Button('Add')
19+
)
20+
)
1721
items = Ul(*todos(), id='todo-list')
1822
logout = A('logout', href=basic_logout(request))
1923
return Titled('Todo list', new_frm, items, logout)
@@ -25,4 +29,3 @@ async def post(todo:Todo): return todos.insert(todo)
2529
async def delete(id:int): todos.delete(id)
2630

2731
serve()
28-

fasthtml/__init__.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,2 @@
11
__version__ = "0.3.8"
22
from .core import *
3-
from .authmw import *
4-
from .components import *
5-
from .xtend import *
6-
from .live_reload import *
7-
from .toaster import *

fasthtml/_modidx.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
'git_url': 'https://github.com/AnswerDotAI/fasthtml',
77
'lib_path': 'fasthtml'},
88
'syms': { 'fasthtml.authmw': {},
9+
'fasthtml.basics': {},
910
'fasthtml.cli': { 'fasthtml.cli._run': ('api/cli.html#_run', 'fasthtml/cli.py'),
1011
'fasthtml.cli.railway_deploy': ('api/cli.html#railway_deploy', 'fasthtml/cli.py'),
1112
'fasthtml.cli.railway_link': ('api/cli.html#railway_link', 'fasthtml/cli.py')},

fasthtml/basics.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .core import *
2+
from .components import *
3+
from .xtend import *
4+

fasthtml/common.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
from fastcore.xml import *
77
from sqlite_minutils import Database
88
from fastlite import *
9-
from . import *
9+
from .basics import *
10+
from .authmw import *
11+
from .live_reload import *
12+
from .toaster import *
1013
from .js import *
1114
from .fastapp import *

fasthtml/components.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from fastcore.utils import *
2121
from fastcore.xml import *
2222
from fastcore.meta import use_kwargs, delegates
23+
from fastcore.test import *
2324
from .core import fh_cfg
2425

2526
import types, json
@@ -53,7 +54,7 @@ def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=Non
5354
if attrmap is None: attrmap=fh_cfg.attrmap
5455
if valmap is None: valmap =fh_cfg.valmap
5556
kwargs['id'],kwargs['cls'],kwargs['title'],kwargs['style'] = id,cls,title,style
56-
tag,c,kw = ft(tag, *c, attrmap=attrmap, valmap=valmap, **kwargs)
57+
tag,c,kw = ft(tag, *c, attrmap=attrmap, valmap=valmap, **kwargs).list
5758
if tag in named and 'id' in kw and 'name' not in kw: kw['name'] = kw['id']
5859
return FT(tag,c,kw, void_=tag in voids)
5960

@@ -85,7 +86,7 @@ def File(fname):
8586
# %% ../nbs/api/01_components.ipynb
8687
def _fill_item(item, obj):
8788
if not isinstance(item,list): return item
88-
tag,cs,attr = item
89+
tag,cs,attr = item.list
8990
if isinstance(cs,tuple): cs = tuple(_fill_item(o, obj) for o in cs)
9091
name = attr.get('name', None)
9192
val = None if name is None else obj.get(name, None)
@@ -117,14 +118,14 @@ def fill_dataclass(src, dest):
117118
# %% ../nbs/api/01_components.ipynb
118119
def find_inputs(e, tags='input', **kw):
119120
"Recursively find all elements in `e` with `tags` and attrs matching `kw`"
120-
if not isinstance(e, (list,tuple)): return []
121+
if not isinstance(e, (list,tuple,FT)): return []
121122
inputs = []
122123
if isinstance(tags,str): tags = [tags]
123124
elif tags is None: tags = []
124125
cs = e
125-
if isinstance(e, list):
126-
tag,cs,attr = e
127-
if e[0] in tags and kw.items()<=e[2].items(): inputs.append(e)
126+
if isinstance(e, FT):
127+
tag,cs,attr = e.list
128+
if tag in tags and kw.items()<=attr.items(): inputs.append(e)
128129
for o in cs: inputs += find_inputs(o, tags, **kw)
129130
return inputs
130131

fasthtml/core.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,11 @@ async def _wrap_req(req, params):
189189

190190
# %% ../nbs/api/00_core.ipynb
191191
def flat_xt(lst):
192-
"Flatten lists, except for `FT`s"
192+
"Flatten lists"
193193
result = []
194194
if isinstance(lst,(FT,str)): lst=[lst]
195195
for item in lst:
196-
if isinstance(item, (list,tuple)) and not isinstance(item, FT): result.extend(item)
196+
if isinstance(item, (list,tuple)): result.extend(item)
197197
else: result.append(item)
198198
return result
199199

@@ -234,7 +234,7 @@ def _wrap_ws(ws, data, params):
234234
# %% ../nbs/api/00_core.ipynb
235235
async def _send_ws(ws, resp):
236236
if not resp: return
237-
res = to_xml(resp, indent=fh_cfg.indent) if isinstance(resp, (list,tuple)) or hasattr(resp, '__ft__') else resp
237+
res = to_xml(resp, indent=fh_cfg.indent) if isinstance(resp, (list,tuple,FT)) or hasattr(resp, '__ft__') else resp
238238
await ws.send_text(res)
239239

240240
def _ws_endp(recv, conn=None, disconn=None, hdrs=None, before=None):
@@ -313,7 +313,7 @@ def _find_targets(req, resp):
313313
def _apply_ft(o):
314314
if isinstance(o, tuple): o = tuple(_apply_ft(c) for c in o)
315315
if hasattr(o, '__ft__'): o = o.__ft__()
316-
if isinstance(o, FT): o[1] = [_apply_ft(c) for c in o[1]]
316+
if isinstance(o, FT): o.children = [_apply_ft(c) for c in o.children]
317317
return o
318318

319319
def _to_xml(req, resp, indent):
@@ -341,7 +341,7 @@ def _resp(req, resp, cls=empty):
341341
if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)
342342
if isinstance(resp, Response): return resp
343343
if cls is not empty: return cls(resp)
344-
if isinstance(resp, (list,tuple,HttpHeader)) or hasattr(resp, '__ft__'): return _xt_resp(req, resp)
344+
if isinstance(resp, (list,tuple,HttpHeader,FT)) or hasattr(resp, '__ft__'): return _xt_resp(req, resp)
345345
if isinstance(resp, str): cls = HTMLResponse
346346
elif isinstance(resp, Mapping): cls = JSONResponse
347347
else:

fasthtml/fastapp.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
import inspect,uvicorn
77
from fastcore.utils import *
88
from fastlite import *
9-
from . import *
9+
from .basics import *
10+
from .starlette import *
1011
from .live_reload import FastHTMLWithLiveReload
1112

1213
# %% auto 0

fasthtml/live_reload.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from starlette.routing import WebSocketRoute
2-
from fasthtml import FastHTML, Script
2+
from fasthtml.basics import FastHTML, Script
33

44
__all__ = ["FastHTMLWithLiveReload"]
55

nbs/api/00_core.ipynb

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@
177177
{
178178
"data": {
179179
"text/plain": [
180-
"datetime.datetime(2024, 8, 14, 14, 0)"
180+
"datetime.datetime(2024, 8, 15, 14, 0)"
181181
]
182182
},
183183
"execution_count": null,
@@ -640,11 +640,11 @@
640640
"source": [
641641
"#| export\n",
642642
"def flat_xt(lst):\n",
643-
" \"Flatten lists, except for `FT`s\"\n",
643+
" \"Flatten lists\"\n",
644644
" result = []\n",
645645
" if isinstance(lst,(FT,str)): lst=[lst]\n",
646646
" for item in lst:\n",
647-
" if isinstance(item, (list,tuple)) and not isinstance(item, FT): result.extend(item)\n",
647+
" if isinstance(item, (list,tuple)): result.extend(item)\n",
648648
" else: result.append(item)\n",
649649
" return result"
650650
]
@@ -737,7 +737,7 @@
737737
"#| export\n",
738738
"async def _send_ws(ws, resp):\n",
739739
" if not resp: return\n",
740-
" res = to_xml(resp, indent=fh_cfg.indent) if isinstance(resp, (list,tuple)) or hasattr(resp, '__ft__') else resp\n",
740+
" res = to_xml(resp, indent=fh_cfg.indent) if isinstance(resp, (list,tuple,FT)) or hasattr(resp, '__ft__') else resp\n",
741741
" await ws.send_text(res)\n",
742742
"\n",
743743
"def _ws_endp(recv, conn=None, disconn=None, hdrs=None, before=None):\n",
@@ -898,7 +898,7 @@
898898
"def _apply_ft(o):\n",
899899
" if isinstance(o, tuple): o = tuple(_apply_ft(c) for c in o)\n",
900900
" if hasattr(o, '__ft__'): o = o.__ft__()\n",
901-
" if isinstance(o, FT): o[1] = [_apply_ft(c) for c in o[1]]\n",
901+
" if isinstance(o, FT): o.children = [_apply_ft(c) for c in o.children]\n",
902902
" return o\n",
903903
"\n",
904904
"def _to_xml(req, resp, indent):\n",
@@ -942,7 +942,7 @@
942942
" if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)\n",
943943
" if isinstance(resp, Response): return resp\n",
944944
" if cls is not empty: return cls(resp)\n",
945-
" if isinstance(resp, (list,tuple,HttpHeader)) or hasattr(resp, '__ft__'): return _xt_resp(req, resp)\n",
945+
" if isinstance(resp, (list,tuple,HttpHeader,FT)) or hasattr(resp, '__ft__'): return _xt_resp(req, resp)\n",
946946
" if isinstance(resp, str): cls = HTMLResponse\n",
947947
" elif isinstance(resp, Mapping): cls = JSONResponse\n",
948948
" else:\n",
@@ -1431,8 +1431,7 @@
14311431
"text": [
14321432
"<!doctype html>\n",
14331433
"\n",
1434-
"<html>\n",
1435-
" <div hx-post=\"/yoyo\">Text.</div>\n",
1434+
"<html><div hx-post=\"/yoyo\">Text.</div>\n",
14361435
"</html>\n",
14371436
"\n"
14381437
]
@@ -1456,10 +1455,8 @@
14561455
"text": [
14571456
"<!doctype html>\n",
14581457
"\n",
1459-
"<html>\n",
1460-
" <body>\n",
1461-
" <div class=\"px-2\" hx-post=\"/hostie?a=b\">Text.</div>\n",
1462-
" </body>\n",
1458+
"<html><body><div class=\"px-2\" hx-post=\"/hostie?a=b\">Text.</div>\n",
1459+
"</body>\n",
14631460
"</html>\n",
14641461
"\n"
14651462
]
@@ -1483,8 +1480,7 @@
14831480
"text": [
14841481
"<!doctype html>\n",
14851482
"\n",
1486-
"<html>\n",
1487-
" <div hx-get=\"/hostie\">Text.</div>\n",
1483+
"<html><div hx-get=\"/hostie\">Text.</div>\n",
14881484
"</html>\n",
14891485
"\n"
14901486
]
@@ -1531,8 +1527,7 @@
15311527
"text": [
15321528
"<!doctype html>\n",
15331529
"\n",
1534-
"<html>\n",
1535-
" <div href=\"/user/Alexis\">Text.</div>\n",
1530+
"<html><div href=\"/user/Alexis\">Text.</div>\n",
15361531
"</html>\n",
15371532
"\n"
15381533
]
@@ -1668,7 +1663,7 @@
16681663
"metadata": {},
16691664
"outputs": [],
16701665
"source": [
1671-
"test_r(cli, '/html/1', '<body>\\n <h4>Next is 2.</h4>\\n</body>\\n', hx=True)\n",
1666+
"test_r(cli, '/html/1', '<body><h4>Next is 2.</h4>\\n</body>\\n', hx=True)\n",
16721667
"test_r(cli, '/static/foo/jph.ico', 'Getting jph.ico from /foo/')\n",
16731668
"test_r(cli, '/models/alexnet', 'alexnet')\n",
16741669
"test_r(cli, '/files/foo', 'foo.txt')\n",
@@ -1873,7 +1868,7 @@
18731868
{
18741869
"data": {
18751870
"text/plain": [
1876-
"'Cookie was set at time 05:03:33.001178'"
1871+
"'Cookie was set at time 10:20:36.329470'"
18771872
]
18781873
},
18791874
"execution_count": null,
@@ -1914,13 +1909,13 @@
19141909
"name": "stdout",
19151910
"output_type": "stream",
19161911
"text": [
1917-
"Set to 2024-08-14 05:03:33.052684\n"
1912+
"Set to 2024-08-15 10:20:36.410886\n"
19181913
]
19191914
},
19201915
{
19211916
"data": {
19221917
"text/plain": [
1923-
"'Session time: 2024-08-14 05:03:33.052684'"
1918+
"'Session time: 2024-08-15 10:20:36.410886'"
19241919
]
19251920
},
19261921
"execution_count": null,
@@ -1948,12 +1943,11 @@
19481943
"\n",
19491944
"<!-- do not remove -->\n",
19501945
"\n",
1951-
"\n",
1952-
"## 0.3.4\n",
1946+
"## 0.3.7\n",
19531947
"\n",
19541948
"### New Features\n",
19551949
"\n",
1956-
"- Experime\n"
1950+
"- Add `relo\n"
19571951
]
19581952
}
19591953
],

0 commit comments

Comments
 (0)