Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 authored and alg747 committed Sep 17, 2024
1 parent 88c579f commit ffdc4c8
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 196 deletions.
5 changes: 5 additions & 0 deletions fasthtml/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@
'fasthtml.core.FastHTML.static_route': ('api/core.html#fasthtml.static_route', 'fasthtml/core.py'),
'fasthtml.core.FastHTML.static_route_exts': ('api/core.html#fasthtml.static_route_exts', 'fasthtml/core.py'),
'fasthtml.core.FastHTML.ws': ('api/core.html#fasthtml.ws', 'fasthtml/core.py'),
'fasthtml.core.FtResponse': ('api/core.html#ftresponse', 'fasthtml/core.py'),
'fasthtml.core.FtResponse.__init__': ('api/core.html#ftresponse.__init__', 'fasthtml/core.py'),
'fasthtml.core.FtResponse.__response__': ('api/core.html#ftresponse.__response__', 'fasthtml/core.py'),
'fasthtml.core.HTTPConnection.url_path_for': ( 'api/core.html#httpconnection.url_path_for',
'fasthtml/core.py'),
'fasthtml.core.HtmxHeaders': ('api/core.html#htmxheaders', 'fasthtml/core.py'),
Expand Down Expand Up @@ -68,6 +71,7 @@
'fasthtml.core._get_htmx': ('api/core.html#_get_htmx', 'fasthtml/core.py'),
'fasthtml.core._handle': ('api/core.html#_handle', 'fasthtml/core.py'),
'fasthtml.core._is_body': ('api/core.html#_is_body', 'fasthtml/core.py'),
'fasthtml.core._is_ft_resp': ('api/core.html#_is_ft_resp', 'fasthtml/core.py'),
'fasthtml.core._list': ('api/core.html#_list', 'fasthtml/core.py'),
'fasthtml.core._mk_list': ('api/core.html#_mk_list', 'fasthtml/core.py'),
'fasthtml.core._mk_locfunc': ('api/core.html#_mk_locfunc', 'fasthtml/core.py'),
Expand All @@ -82,6 +86,7 @@
'fasthtml.core._wrap_req': ('api/core.html#_wrap_req', 'fasthtml/core.py'),
'fasthtml.core._wrap_ws': ('api/core.html#_wrap_ws', 'fasthtml/core.py'),
'fasthtml.core._ws_endp': ('api/core.html#_ws_endp', 'fasthtml/core.py'),
'fasthtml.core._xt_cts': ('api/core.html#_xt_cts', 'fasthtml/core.py'),
'fasthtml.core._xt_resp': ('api/core.html#_xt_resp', 'fasthtml/core.py'),
'fasthtml.core.cookie': ('api/core.html#cookie', 'fasthtml/core.py'),
'fasthtml.core.date': ('api/core.html#date', 'fasthtml/core.py'),
Expand Down
52 changes: 36 additions & 16 deletions fasthtml/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
__all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmx_resps', 'htmxsrc', 'htmxwssrc', 'fhjsscr', 'htmxctsrc', 'surrsrc', 'scopesrc',
'viewport', 'charset', 'all_meths', 'date', 'snake2hyphens', 'HtmxHeaders', 'str2int', 'HttpHeader',
'HtmxResponseHeaders', 'form2dict', 'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown', 'WS_RouteX',
'uri', 'decode_uri', 'flat_tuple', 'Redirect', 'RouteX', 'RouterX', 'get_key', 'FastHTML', 'serve', 'cookie',
'reg_re_param', 'MiddlewareBase', 'Client']
'uri', 'decode_uri', 'flat_tuple', 'Redirect', 'RouteX', 'RouterX', 'get_key', 'FastHTML', 'serve', 'Client',
'cookie', 'reg_re_param', 'MiddlewareBase', 'FtResponse']

# %% ../nbs/api/00_core.ipynb
import json,uuid,inspect,types,uvicorn,signal,asyncio,threading
Expand Down Expand Up @@ -358,7 +358,7 @@ def flat_tuple(o):
return tuple(result)

# %% ../nbs/api/00_core.ipynb
def _xt_resp(req, resp):
def _xt_cts(req, resp):
resp = flat_tuple(resp)
resp = resp + tuple(getattr(req, 'injects', ()))
http_hdrs,resp = partition(resp, risinstance(HttpHeader))
Expand All @@ -368,17 +368,25 @@ def _xt_resp(req, resp):
if resp and 'hx-request' not in req.headers and not any(getattr(o, 'tag', '')=='html' for o in resp):
if not titles: titles = [Title('FastHTML page')]
resp = Html(Head(*titles, *flat_xt(req.hdrs)), Body(bdy, *flat_xt(req.ftrs), **req.bodykw), **req.htmlkw)
return HTMLResponse(_to_xml(req, resp, indent=fh_cfg.indent), headers=http_hdrs)
return _to_xml(req, resp, indent=fh_cfg.indent), http_hdrs

# %% ../nbs/api/00_core.ipynb
def _xt_resp(req, resp):
cts,http_hdrs = _xt_cts(req, resp)
return HTMLResponse(cts, headers=http_hdrs)

# %% ../nbs/api/00_core.ipynb
def _is_ft_resp(resp): return isinstance(resp, (list,tuple,HttpHeader,FT)) or hasattr(resp, '__ft__')

# %% ../nbs/api/00_core.ipynb
def _resp(req, resp, cls=empty):
if not resp: resp=()
if hasattr(resp, '__response__'): resp = resp.__response__(req)
if cls in (Any,FT): cls=empty
if isinstance(resp, FileResponse) and not os.path.exists(resp.path): raise HTTPException(404, resp.path)
if isinstance(resp, Response): return resp
if cls is not empty: return cls(resp)
if isinstance(resp, (list,tuple,HttpHeader,FT)) or hasattr(resp, '__ft__'): return _xt_resp(req, resp)
if isinstance(resp, Response): return resp
if _is_ft_resp(resp): return _xt_resp(req, resp)
if isinstance(resp, str): cls = HTMLResponse
elif isinstance(resp, Mapping): cls = JSONResponse
else:
Expand Down Expand Up @@ -563,6 +571,18 @@ def serve(
print(f'Link: http://{"localhost" if host=="0.0.0.0" else host}:{port}')
uvicorn.run(f'{appname}:{app}', host=host, port=port, reload=reload, reload_includes=reload_includes, reload_excludes=reload_excludes)

# %% ../nbs/api/00_core.ipynb
class Client:
"A simple httpx ASGI client that doesn't require `async`"
def __init__(self, app, url="http://testserver"):
self.cli = AsyncClient(transport=ASGITransport(app), base_url=url)

def _sync(self, method, url, **kwargs):
async def _request(): return await self.cli.request(method, url, **kwargs)
with from_thread.start_blocking_portal() as portal: return portal.call(_request)

for o in ('get', 'post', 'delete', 'put', 'patch', 'options'): setattr(Client, o, partialmethod(Client._sync, o))

# %% ../nbs/api/00_core.ipynb
def cookie(key: str, value="", max_age=None, expires=None, path="/", domain=None, secure=False, httponly=False, samesite="lax",):
"Create a 'set-cookie' `HttpHeader`"
Expand Down Expand Up @@ -613,13 +633,13 @@ async def __call__(self, scope, receive, send) -> None:
return HTTPConnection(scope)

# %% ../nbs/api/00_core.ipynb
class Client:
"A simple httpx ASGI client that doesn't require `async`"
def __init__(self, app, url="http://testserver"):
self.cli = AsyncClient(transport=ASGITransport(app), base_url=url)

def _sync(self, method, url, **kwargs):
async def _request(): return await self.cli.request(method, url, **kwargs)
with from_thread.start_blocking_portal() as portal: return portal.call(_request)

for o in ('get', 'post', 'delete', 'put', 'patch', 'options'): setattr(Client, o, partialmethod(Client._sync, o))
class FtResponse:
"Wrap an FT response with any Starlette `Response`"
def __init__(self, content, status_code:int=200, headers=None, cls=HTMLResponse, media_type:str|None=None, background=None):
self.content,self.status_code,self.headers = content,status_code,headers
self.cls,self.media_type,self.background = cls,media_type,background

def __response__(self, req):
cts,httphdrs = _xt_cts(req, self.content)
headers = {**(self.headers or {}), **httphdrs}
return self.cls(cts, status_code=self.status_code, headers=headers, media_type=self.media_type, background=self.background)
24 changes: 21 additions & 3 deletions fasthtml/xtend.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/02_xtend.ipynb.

# %% auto 0
__all__ = ['A', 'Form', 'AX', 'Hidden', 'CheckboxX', 'Script', 'Style', 'double_braces', 'undouble_braces', 'loose_format',
'ScriptX', 'replace_css_vars', 'StyleX', 'On', 'Prev', 'Now', 'AnyNow', 'run_js', 'HtmxOn', 'Titled',
'Socials', 'Favicon', 'jsd', 'clear']
__all__ = ['sid_scr', 'A', 'Form', 'AX', 'Hidden', 'CheckboxX', 'Script', 'Style', 'double_braces', 'undouble_braces',
'loose_format', 'ScriptX', 'replace_css_vars', 'StyleX', 'On', 'Prev', 'Now', 'AnyNow', 'run_js', 'HtmxOn',
'Titled', 'Socials', 'Favicon', 'jsd', 'clear']

# %% ../nbs/api/02_xtend.ipynb
from dataclasses import dataclass, asdict
Expand Down Expand Up @@ -190,3 +190,21 @@ def jsd(org, repo, root, path, prov='gh', typ='script', ver=None, esm=False, **k

# %% ../nbs/api/02_xtend.ipynb
def clear(id): return Div(hx_swap_oob='innerHTML', id=id)

# %% ../nbs/api/02_xtend.ipynb
sid_scr = Script('''
function uuid() {
return [...crypto.getRandomValues(new Uint8Array(10))].map(b=>b.toString(36)).join('');
}
sessionStorage.setItem("sid", sessionStorage.getItem("sid") || uuid());
htmx.on("htmx:configRequest", (e) => {
const sid = sessionStorage.getItem("sid");
if (sid) {
const url = new URL(e.detail.path, window.location.origin);
url.searchParams.set('sid', sid);
e.detail.path = url.pathname + url.search;
}
});
''')
Loading

0 comments on commit ffdc4c8

Please sign in to comment.