Skip to content

Commit abbdd03

Browse files
committed
fixes #858
1 parent bec9fcd commit abbdd03

5 files changed

Lines changed: 513 additions & 116 deletions

File tree

fasthtml/_modidx.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
'fasthtml.core.ApiReturn.__init__': ('api/core.html#apireturn.__init__', 'fasthtml/core.py'),
4141
'fasthtml.core.Beforeware': ('api/core.html#beforeware', 'fasthtml/core.py'),
4242
'fasthtml.core.Beforeware.__init__': ('api/core.html#beforeware.__init__', 'fasthtml/core.py'),
43+
'fasthtml.core.Beforeware.__repr__': ('api/core.html#beforeware.__repr__', 'fasthtml/core.py'),
4344
'fasthtml.core.Client': ('api/core.html#client', 'fasthtml/core.py'),
4445
'fasthtml.core.Client.__init__': ('api/core.html#client.__init__', 'fasthtml/core.py'),
4546
'fasthtml.core.Client._sync': ('api/core.html#client._sync', 'fasthtml/core.py'),
@@ -133,13 +134,17 @@
133134
'fasthtml.core._wrap_ws': ('api/core.html#_wrap_ws', 'fasthtml/core.py'),
134135
'fasthtml.core._ws_endp': ('api/core.html#_ws_endp', 'fasthtml/core.py'),
135136
'fasthtml.core._xt_cts': ('api/core.html#_xt_cts', 'fasthtml/core.py'),
137+
'fasthtml.core.add_sig_param': ('api/core.html#add_sig_param', 'fasthtml/core.py'),
136138
'fasthtml.core.cookie': ('api/core.html#cookie', 'fasthtml/core.py'),
137139
'fasthtml.core.decode_uri': ('api/core.html#decode_uri', 'fasthtml/core.py'),
138140
'fasthtml.core.def_hdrs': ('api/core.html#def_hdrs', 'fasthtml/core.py'),
139141
'fasthtml.core.flat_tuple': ('api/core.html#flat_tuple', 'fasthtml/core.py'),
140142
'fasthtml.core.flat_xt': ('api/core.html#flat_xt', 'fasthtml/core.py'),
141143
'fasthtml.core.form2dict': ('api/core.html#form2dict', 'fasthtml/core.py'),
142144
'fasthtml.core.get_key': ('api/core.html#get_key', 'fasthtml/core.py'),
145+
'fasthtml.core.into': ('api/core.html#into', 'fasthtml/core.py'),
146+
'fasthtml.core.into.__call__': ('api/core.html#into.__call__', 'fasthtml/core.py'),
147+
'fasthtml.core.into.__init__': ('api/core.html#into.__init__', 'fasthtml/core.py'),
143148
'fasthtml.core.is_full_page': ('api/core.html#is_full_page', 'fasthtml/core.py'),
144149
'fasthtml.core.nested_name': ('api/core.html#nested_name', 'fasthtml/core.py'),
145150
'fasthtml.core.noop_body': ('api/core.html#noop_body', 'fasthtml/core.py'),

fasthtml/core.py

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown', 'uri', 'decode_uri', 'flat_tuple', 'noop_body',
1010
'respond', 'is_full_page', 'Redirect', 'get_key', 'qp', 'def_hdrs', 'Lifespan', 'FastHTML', 'HostRoute',
1111
'nested_name', 'serve', 'Client', 'RouteFuncs', 'APIRouter', 'cookie', 'reg_re_param', 'StaticNoCache',
12-
'MiddlewareBase', 'FtResponse', 'unqid']
12+
'add_sig_param', 'into', 'MiddlewareBase', 'FtResponse', 'unqid']
1313

1414
# %% ../nbs/api/00_core.ipynb #23503b9e
1515
import json,uuid,inspect,types,asyncio,inspect,random,contextlib,httpx,itsdangerous,uvicorn
@@ -163,12 +163,15 @@ async def parse_form(req: Request) -> FormData:
163163
return await req.json() if ctype == 'application/json' else await req.form()
164164

165165

166-
# %% ../nbs/api/00_core.ipynb #089fe388
166+
# %% ../nbs/api/00_core.ipynb #0caedd04
167167
async def _from_body(conn, p, data):
168168
"Create an instance of the annotated type from pre-parsed `data`"
169169
anno = p.annotation
170170
ctor = getattr(anno, '__from_request__', None)
171-
if ctor: return await maybe_await(ctor(data, conn))
171+
if ctor:
172+
ps = {k:v for k,v in _params(ctor).items() if k != 'cls'}
173+
kwargs = await _find_ps(conn, data, conn.headers, ps)
174+
return await maybe_await(ctor(**kwargs))
172175
d = _annotations(anno)
173176
cargs = {k: _form_arg(k, v, d) for k, v in data.items() if not d or k in d}
174177
return anno(**cargs)
@@ -260,6 +263,7 @@ def flat_xt(lst):
260263
# %% ../nbs/api/00_core.ipynb #aacff5ac
261264
class Beforeware:
262265
def __init__(self, f, skip=None): self.f,self.skip = f,skip or []
266+
def __repr__(self): return f'Beforeware({self.f}, skip={self.skip})'
263267

264268
# %% ../nbs/api/00_core.ipynb #78c3c357
265269
async def _handle(f, *args, **kwargs):
@@ -904,6 +908,43 @@ def file_response(self, *args, **kwargs):
904908
resp.headers.setdefault("Cache-Control", "no-cache")
905909
return resp
906910

911+
# %% ../nbs/api/00_core.ipynb #7189daf8
912+
from functools import wraps
913+
from inspect import signature, isawaitable
914+
915+
# %% ../nbs/api/00_core.ipynb #7eed23b7
916+
def add_sig_param(f, name, typ=NoneType, kind=Parameter.KEYWORD_ONLY, default=Parameter.empty):
917+
"Add a parameter to a function's signature"
918+
sig = signature(f)
919+
if name in sig.parameters: return f
920+
kw = {} if default is Parameter.empty else {'default': default}
921+
new_params = list(sig.parameters.values()) + [Parameter(name, kind, **kw)]
922+
f.__signature__ = sig.replace(parameters=new_params)
923+
f.__annotations__[name] = typ
924+
return f
925+
926+
# %% ../nbs/api/00_core.ipynb #9e5a9e88
927+
class into:
928+
"Decorator to pass a route's return value into `func`, with keyword params added to the route signature"
929+
def __init__(self, func):
930+
self.func = func
931+
self.params = {k:p for k,p in signature(func).parameters.items()
932+
if p.kind not in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD)}
933+
934+
def __call__(self, f):
935+
@wraps(f)
936+
async def _inner(*args, **kw):
937+
extra = {k: kw.pop(k, None) for k in self.params}
938+
res = f(*args, **kw)
939+
if isawaitable(res): res = await res
940+
res = self.func(*tuplify(res), **extra)
941+
if isawaitable(res): res = await res
942+
return res
943+
for k,p in self.params.items():
944+
anno = p.annotation if p.annotation is not Parameter.empty else NoneType
945+
add_sig_param(_inner, k, anno, default=p.default)
946+
return _inner
947+
907948
# %% ../nbs/api/00_core.ipynb #1960d7ff
908949
class MiddlewareBase:
909950
async def __call__(self, scope, receive, send) -> None:

0 commit comments

Comments
 (0)