Skip to content

Commit 94a405b

Browse files
committed
fixes #513
1 parent 5eac7ba commit 94a405b

File tree

3 files changed

+49
-31
lines changed

3 files changed

+49
-31
lines changed

fasthtml/core.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -73,21 +73,22 @@ def _get_htmx(h):
7373
return HtmxHeaders(**res)
7474

7575
# %% ../nbs/api/00_core.ipynb
76-
def _mk_list(t, v): return [t(o) for o in v]
76+
def _mk_list(t, v): return [t(o) for o in listify(v)]
7777

7878
# %% ../nbs/api/00_core.ipynb
7979
fh_cfg = AttrDict(indent=True)
8080

8181
# %% ../nbs/api/00_core.ipynb
82-
def _fix_anno(t):
82+
def _fix_anno(t, o):
8383
"Create appropriate callable type for casting a `str` to type `t` (or first type in `t` if union)"
8484
origin = get_origin(t)
8585
if origin is Union or origin is UnionType or origin in (list,List):
8686
t = first(o for o in get_args(t) if o!=type(None))
8787
d = {bool: str2bool, int: str2int, date: str2date, UploadFile: noop}
8888
res = d.get(t, t)
89-
if origin in (list,List): return partial(_mk_list, res)
90-
return lambda o: res(o[-1]) if isinstance(o,(list,tuple)) else res(o)
89+
if origin in (list,List): return _mk_list(res, o)
90+
if not isinstance(o, (str,list,tuple)): return o
91+
return res(o[-1]) if isinstance(o,(list,tuple)) else res(o)
9192

9293
# %% ../nbs/api/00_core.ipynb
9394
def _form_arg(k, v, d):
@@ -97,7 +98,7 @@ def _form_arg(k, v, d):
9798
# This is the type we want to cast `v` to
9899
anno = d.get(k, None)
99100
if not anno: return v
100-
return _fix_anno(anno)(v)
101+
return _fix_anno(anno, v)
101102

102103
# %% ../nbs/api/00_core.ipynb
103104
@dataclass
@@ -195,9 +196,8 @@ async def _find_p(req, arg:str, p:Parameter):
195196
# If we have a default, return that if we have no value
196197
if res in (empty,None): res = p.default
197198
# We can cast str and list[str] to types; otherwise just return what we have
198-
if not isinstance(res, (list,str)) or anno is empty: return res
199-
anno = _fix_anno(anno)
200-
try: return anno(res)
199+
if anno is empty: return res
200+
try: return _fix_anno(anno, res)
201201
except ValueError: raise HTTPException(404, req.url.path) from None
202202

203203
async def _wrap_req(req, params):
@@ -241,8 +241,7 @@ def _find_wsp(ws, data, hdrs, arg:str, p:Parameter):
241241
if res is empty or res is None: res = p.default
242242
# We can cast str and list[str] to types; otherwise just return what we have
243243
if not isinstance(res, (list,str)) or anno is empty: return res
244-
anno = _fix_anno(anno)
245-
return [anno(o) for o in res] if isinstance(res,list) else anno(res)
244+
return [_fix_anno(anno, o) for o in res] if isinstance(res,list) else _fix_anno(anno, res)
246245

247246
def _wrap_ws(ws, data, params):
248247
hdrs = {k.lower().replace('-','_'):v for k,v in data.pop('HEADERS', {}).items()}

nbs/api/00_core.ipynb

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@
131131
{
132132
"data": {
133133
"text/plain": [
134-
"datetime.datetime(2024, 10, 16, 14, 0)"
134+
"datetime.datetime(2024, 10, 19, 14, 0)"
135135
]
136136
},
137137
"execution_count": null,
@@ -280,7 +280,7 @@
280280
"outputs": [],
281281
"source": [
282282
"#| export\n",
283-
"def _mk_list(t, v): return [t(o) for o in v]"
283+
"def _mk_list(t, v): return [t(o) for o in listify(v)]"
284284
]
285285
},
286286
{
@@ -310,15 +310,16 @@
310310
"outputs": [],
311311
"source": [
312312
"#| export\n",
313-
"def _fix_anno(t):\n",
313+
"def _fix_anno(t, o):\n",
314314
" \"Create appropriate callable type for casting a `str` to type `t` (or first type in `t` if union)\"\n",
315315
" origin = get_origin(t)\n",
316316
" if origin is Union or origin is UnionType or origin in (list,List):\n",
317317
" t = first(o for o in get_args(t) if o!=type(None))\n",
318318
" d = {bool: str2bool, int: str2int, date: str2date, UploadFile: noop}\n",
319319
" res = d.get(t, t)\n",
320-
" if origin in (list,List): return partial(_mk_list, res)\n",
321-
" return lambda o: res(o[-1]) if isinstance(o,(list,tuple)) else res(o)"
320+
" if origin in (list,List): return _mk_list(res, o)\n",
321+
" if not isinstance(o, (str,list,tuple)): return o\n",
322+
" return res(o[-1]) if isinstance(o,(list,tuple)) else res(o)"
322323
]
323324
},
324325
{
@@ -328,12 +329,12 @@
328329
"metadata": {},
329330
"outputs": [],
330331
"source": [
331-
"test_eq(_fix_anno(Union[str,None])('a'), 'a')\n",
332-
"test_eq(_fix_anno(float)(0.9), 0.9)\n",
333-
"test_eq(_fix_anno(int)('1'), 1)\n",
334-
"test_eq(_fix_anno(int)(['1','2']), 2)\n",
335-
"test_eq(_fix_anno(list[int])(['1','2']), [1,2])\n",
336-
"test_eq(_fix_anno(list[int])('1'), [1])"
332+
"test_eq(_fix_anno(Union[str,None], 'a'), 'a')\n",
333+
"test_eq(_fix_anno(float, 0.9), 0.9)\n",
334+
"test_eq(_fix_anno(int, '1'), 1)\n",
335+
"test_eq(_fix_anno(int, ['1','2']), 2)\n",
336+
"test_eq(_fix_anno(list[int], ['1','2']), [1,2])\n",
337+
"test_eq(_fix_anno(list[int], '1'), [1])"
337338
]
338339
},
339340
{
@@ -351,7 +352,7 @@
351352
" # This is the type we want to cast `v` to\n",
352353
" anno = d.get(k, None)\n",
353354
" if not anno: return v\n",
354-
" return _fix_anno(anno)(v)"
355+
" return _fix_anno(anno, v)"
355356
]
356357
},
357358
{
@@ -651,9 +652,8 @@
651652
" # If we have a default, return that if we have no value\n",
652653
" if res in (empty,None): res = p.default\n",
653654
" # We can cast str and list[str] to types; otherwise just return what we have\n",
654-
" if not isinstance(res, (list,str)) or anno is empty: return res\n",
655-
" anno = _fix_anno(anno)\n",
656-
" try: return anno(res)\n",
655+
" if anno is empty: return res\n",
656+
" try: return _fix_anno(anno, res)\n",
657657
" except ValueError: raise HTTPException(404, req.url.path) from None\n",
658658
"\n",
659659
"async def _wrap_req(req, params):\n",
@@ -805,8 +805,7 @@
805805
" if res is empty or res is None: res = p.default\n",
806806
" # We can cast str and list[str] to types; otherwise just return what we have\n",
807807
" if not isinstance(res, (list,str)) or anno is empty: return res\n",
808-
" anno = _fix_anno(anno)\n",
809-
" return [anno(o) for o in res] if isinstance(res,list) else anno(res)\n",
808+
" return [_fix_anno(anno, o) for o in res] if isinstance(res,list) else _fix_anno(anno, res)\n",
810809
"\n",
811810
"def _wrap_ws(ws, data, params):\n",
812811
" hdrs = {k.lower().replace('-','_'):v for k,v in data.pop('HEADERS', {}).items()}\n",
@@ -2233,6 +2232,27 @@
22332232
"print(res.text)"
22342233
]
22352234
},
2235+
{
2236+
"cell_type": "code",
2237+
"execution_count": null,
2238+
"id": "28a99667",
2239+
"metadata": {},
2240+
"outputs": [
2241+
{
2242+
"name": "stdout",
2243+
"output_type": "stream",
2244+
"text": [
2245+
"200\n",
2246+
"content1\n"
2247+
]
2248+
}
2249+
],
2250+
"source": [
2251+
"res = cli.post('/uploads', files=[files[0]])\n",
2252+
"print(res.status_code)\n",
2253+
"print(res.text)"
2254+
]
2255+
},
22362256
{
22372257
"cell_type": "code",
22382258
"execution_count": null,
@@ -2243,13 +2263,13 @@
22432263
"name": "stdout",
22442264
"output_type": "stream",
22452265
"text": [
2246-
"Set to 2024-10-16 15:38:25.588198\n"
2266+
"Set to 2024-10-19 15:14:43.250650\n"
22472267
]
22482268
},
22492269
{
22502270
"data": {
22512271
"text/plain": [
2252-
"'Session time: 2024-10-16 15:38:25.588198'"
2272+
"'Session time: 2024-10-19 15:14:43.250650'"
22532273
]
22542274
},
22552275
"execution_count": null,
@@ -2480,7 +2500,7 @@
24802500
{
24812501
"data": {
24822502
"text/plain": [
2483-
"'Cookie was set at time 15:38:25.962118'"
2503+
"'Cookie was set at time 15:14:43.683602'"
24842504
]
24852505
},
24862506
"execution_count": null,

nbs/api/04_pico.ipynb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@
7373
"data": {
7474
"text/html": [
7575
"<link rel=\"stylesheet\" href=\"https://cdn.jsdelivr.net/npm/@picocss/pico@latest/css/pico.conditional.min.css\">\n",
76-
"\n",
7776
"<style>:root { --pico-font-size: 100%; }</style>\n"
7877
],
7978
"text/plain": [

0 commit comments

Comments
 (0)