Skip to content

Commit

Permalink
genius or madness -- i am not sure...
Browse files Browse the repository at this point in the history
  • Loading branch information
jph00 committed May 30, 2024
1 parent 414df8a commit dfc1391
Show file tree
Hide file tree
Showing 4 changed files with 217 additions and 225 deletions.
1 change: 1 addition & 0 deletions fasthtml/_modidx.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
'fasthtml.components.xt_html': ('components.html#xt_html', 'fasthtml/components.py'),
'fasthtml.components.xt_hx': ('components.html#xt_hx', 'fasthtml/components.py')},
'fasthtml.core': { 'fasthtml.core.FastHTML': ('core.html#fasthtml', 'fasthtml/core.py'),
'fasthtml.core.FastHTML.__getitem__': ('core.html#fasthtml.__getitem__', 'fasthtml/core.py'),
'fasthtml.core.FastHTML.__init__': ('core.html#fasthtml.__init__', 'fasthtml/core.py'),
'fasthtml.core.FastHTML.route': ('core.html#fasthtml.route', 'fasthtml/core.py'),
'fasthtml.core.HtmxHeaders': ('core.html#htmxheaders', 'fasthtml/core.py'),
Expand Down
26 changes: 19 additions & 7 deletions fasthtml/core.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/00_core.ipynb.

# %% auto 0
__all__ = ['empty', 'htmx_hdrs', 'htmxscr', 'is_namedtuple', 'date', 'snake2hyphens', 'HtmxHeaders', 'str2int', 'RouteX',
'RouterX', 'FastHTML', 'reg_re_param']
__all__ = ['empty', 'htmx_hdrs', 'htmxscr', 'all_meths', 'is_namedtuple', 'date', 'snake2hyphens', 'HtmxHeaders', 'str2int',
'RouteX', 'RouterX', 'FastHTML', 'reg_re_param']

# %% ../nbs/00_core.ipynb 2
import json, dateutil
Expand Down Expand Up @@ -122,10 +122,9 @@ async def _find_p(req, arg:str, p):
if not res: res = req.cookies.get(arg, None)
if not res: res = req.headers.get(snake2hyphens(arg), None)
if not res: res = p.default
if res is empty: return None
anno = _fix_anno(anno)
if res is not None and anno is not empty: res = anno(res)
return res
if res is empty or res is None: return None
if not isinstance(res, str) or anno is empty: return res
return _fix_anno(anno)(res)

# %% ../nbs/00_core.ipynb 14
async def _wrap_req(req, params):
Expand Down Expand Up @@ -183,6 +182,7 @@ def __init__(self, routes=None, redirect_slashes=True, default=None, on_startup=
def add_route( self, path: str, endpoint: callable, methods=None, name=None, include_in_schema=True):
route = RouteX(path, endpoint=endpoint, methods=methods, name=name, include_in_schema=include_in_schema,
hdrs=self.hdrs, **self.bodykw)
self.routes = [o for o in self.routes if o.methods!=methods or o.path!=path]
self.routes.append(route)

# %% ../nbs/00_core.ipynb 20
Expand All @@ -191,21 +191,33 @@ def add_route( self, path: str, endpoint: callable, methods=None, name=None, inc
integrity="sha384-ujb1lZYygJmzgSwoxRggbCHcjc0rB2XoQrxeTUQyRjrOnlCoYta87iKBWq3EsdM2")

# %% ../nbs/00_core.ipynb 21
all_meths = 'get post put delete patch head trace options'.split()

class FastHTML(Starlette):
def __init__(self, debug=False, routes=None, middleware=None, exception_handlers=None,
on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, **bodykw):
super().__init__(debug, routes, middleware, exception_handlers, on_startup, on_shutdown, lifespan=lifespan)
hdrs = list([] if hdrs is None else hdrs) + [htmxscr]
self.router = RouterX(routes, on_startup=on_startup, on_shutdown=on_shutdown, lifespan=lifespan, hdrs=hdrs, **bodykw)

def __getitem__(self, path):
name = None
if isinstance(path, tuple): path,name = path
def f(func):
meth = func.__name__
if meth not in all_meths: meth='get'
self.router.add_route(path, func, methods=[meth], name=name)
return func
return f

def route(self, path:str, methods=None, name=None, include_in_schema=True):
if isinstance(methods,str): methods=[methods]
def f(func):
self.router.add_route(path, func, methods=methods, name=name, include_in_schema=include_in_schema)
return func
return f

for o in 'get post put delete patch head trace options'.split():
for o in all_meths:
setattr(FastHTML, o, partialmethod(FastHTML.route, methods=o.capitalize()))

# %% ../nbs/00_core.ipynb 22
Expand Down
158 changes: 96 additions & 62 deletions nbs/00_core.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -240,10 +240,9 @@
" if not res: res = req.cookies.get(arg, None)\n",
" if not res: res = req.headers.get(snake2hyphens(arg), None)\n",
" if not res: res = p.default\n",
" if res is empty: return None\n",
" anno = _fix_anno(anno)\n",
" if res is not None and anno is not empty: res = anno(res)\n",
" return res"
" if res is empty or res is None: return None\n",
" if not isinstance(res, str) or anno is empty: return res\n",
" return _fix_anno(anno)(res)"
]
},
{
Expand Down Expand Up @@ -349,6 +348,7 @@
" def add_route( self, path: str, endpoint: callable, methods=None, name=None, include_in_schema=True):\n",
" route = RouteX(path, endpoint=endpoint, methods=methods, name=name, include_in_schema=include_in_schema,\n",
" hdrs=self.hdrs, **self.bodykw)\n",
" self.routes = [o for o in self.routes if o.methods!=methods or o.path!=path]\n",
" self.routes.append(route)"
]
},
Expand All @@ -373,21 +373,33 @@
"outputs": [],
"source": [
"#| export\n",
"all_meths = 'get post put delete patch head trace options'.split()\n",
"\n",
"class FastHTML(Starlette):\n",
" def __init__(self, debug=False, routes=None, middleware=None, exception_handlers=None,\n",
" on_startup=None, on_shutdown=None, lifespan=None, hdrs=None, **bodykw):\n",
" super().__init__(debug, routes, middleware, exception_handlers, on_startup, on_shutdown, lifespan=lifespan)\n",
" hdrs = list([] if hdrs is None else hdrs) + [htmxscr]\n",
" self.router = RouterX(routes, on_startup=on_startup, on_shutdown=on_shutdown, lifespan=lifespan, hdrs=hdrs, **bodykw)\n",
"\n",
" def __getitem__(self, path):\n",
" name = None\n",
" if isinstance(path, tuple): path,name = path\n",
" def f(func):\n",
" meth = func.__name__\n",
" if meth not in all_meths: meth='get'\n",
" self.router.add_route(path, func, methods=[meth], name=name)\n",
" return func\n",
" return f\n",
"\n",
" def route(self, path:str, methods=None, name=None, include_in_schema=True):\n",
" if isinstance(methods,str): methods=[methods]\n",
" def f(func):\n",
" self.router.add_route(path, func, methods=methods, name=name, include_in_schema=include_in_schema)\n",
" return func\n",
" return f\n",
"\n",
"for o in 'get post put delete patch head trace options'.split():\n",
"for o in all_meths:\n",
" setattr(FastHTML, o, partialmethod(FastHTML.route, methods=o.capitalize()))"
]
},
Expand Down Expand Up @@ -432,24 +444,11 @@
{
"cell_type": "code",
"execution_count": null,
"id": "b6586a02",
"metadata": {},
"outputs": [],
"source": [
"def test_r(cli, path, exp, meth='get', **kwargs): test_eq(getattr(cli, meth)(path, **kwargs).text, exp)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "ef78bea8",
"id": "66b8b1de",
"metadata": {},
"outputs": [],
"source": [
"app = FastHTML()\n",
"app.chk = 'foo'\n",
"ModelName = str_enum('ModelName', \"alexnet\", \"resnet\", \"lenet\")\n",
"fake_db = [{\"name\": \"Foo\"}, {\"name\": \"Bar\"}]"
"app = FastHTML()"
]
},
{
Expand All @@ -467,17 +466,6 @@
"execution_count": null,
"id": "3edc4781",
"metadata": {},
"outputs": [],
"source": [
"@app.get(\"/hi\")\n",
"def _(): return 'Hi there'"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c242280d",
"metadata": {},
"outputs": [
{
"data": {
Expand All @@ -491,25 +479,41 @@
}
],
"source": [
"@app[\"/hi\"]\n",
"def get(): return 'Hi there'\n",
"\n",
"r = cli.get('/hi')\n",
"r.text"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bb4f8b67",
"id": "07fe773b",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Postal'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@app.get(\"/\")\n",
"def _(req): return req.headers['host']"
"@app[\"/hi\"]\n",
"def post(): return 'Postal'\n",
"\n",
"cli.post('/hi').text"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5b6224cc",
"id": "bb4f8b67",
"metadata": {},
"outputs": [
{
Expand All @@ -524,6 +528,9 @@
}
],
"source": [
"@app.get(\"/\")\n",
"def show_host(req): return req.headers['host']\n",
"\n",
"cli.get('/').text"
]
},
Expand All @@ -532,22 +539,35 @@
"execution_count": null,
"id": "64343367",
"metadata": {},
"outputs": [],
"outputs": [
{
"data": {
"text/plain": [
"'Good day to you, Alexis!'"
]
},
"execution_count": null,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"@app.get('/user/{nm}')\n",
"def _(nm:str): return f\"Good day to you, {nm}!\""
"@app['/user/{nm}', 'gday']\n",
"def get(nm:str): return f\"Good day to you, {nm}!\"\n",
"\n",
"cli.get('/user/Alexis').text"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "314cacf1",
"id": "db0281cf",
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Good day to you, Alexis!'"
"'/user/Jeremy'"
]
},
"execution_count": null,
Expand All @@ -556,7 +576,21 @@
}
],
"source": [
"cli.get('/user/Alexis').text"
"app.router.url_path_for('gday', nm='Jeremy')"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6b022adb",
"metadata": {},
"outputs": [],
"source": [
"def test_r(cli, path, exp, meth='get', **kwargs): test_eq(getattr(cli, meth)(path, **kwargs).text, exp)\n",
"\n",
"app.chk = 'foo'\n",
"ModelName = str_enum('ModelName', \"alexnet\", \"resnet\", \"lenet\")\n",
"fake_db = [{\"name\": \"Foo\"}, {\"name\": \"Bar\"}]"
]
},
{
Expand All @@ -566,22 +600,22 @@
"metadata": {},
"outputs": [],
"source": [
"@app.get('/html/{idx}')\n",
"async def get_html(idx:int): return Body(H4(f'Next is {idx+1}.'))\n",
"@app['/html/{idx}']\n",
"async def get(idx:int): return Body(H4(f'Next is {idx+1}.'))\n",
"\n",
"reg_re_param(\"imgext\", \"ico|gif|jpg|jpeg|webm\")\n",
"\n",
"@app.get(r'/static/{path:path}{fn}.{ext:imgext}')\n",
"def get_img(fn:str, path:str, ext:str): return f\"Getting {fn}.{ext} from /{path}\"\n",
"@app[r'/static/{path:path}{fn}.{ext:imgext}']\n",
"def get(fn:str, path:str, ext:str): return f\"Getting {fn}.{ext} from /{path}\"\n",
"\n",
"@app.get(\"/models/{nm}\")\n",
"def model(nm:ModelName): return nm\n",
"@app[\"/models/{nm}\"]\n",
"def get(nm:ModelName): return nm\n",
"\n",
"@app.get(\"/files/{path}\")\n",
"async def txt(path: Path): return path.with_suffix('.txt')\n",
"@app[\"/files/{path}\"]\n",
"async def get(path: Path): return path.with_suffix('.txt')\n",
"\n",
"@app.get(\"/items/\")\n",
"def read_item(idx:int|None = 0): return fake_db[idx]"
"@app[\"/items/\"]\n",
"def get(idx:int|None = 0): return fake_db[idx]"
]
},
{
Expand All @@ -596,7 +630,7 @@
"test_r(cli, '/models/alexnet', 'alexnet')\n",
"test_r(cli, '/files/foo', 'foo.txt')\n",
"test_r(cli, '/items/?idx=1', '{\"name\":\"Bar\"}')\n",
"# test_r(cli, '/items/', '{\"name\":\"Foo\"}')"
"test_r(cli, '/items/', '{\"name\":\"Foo\"}')"
]
},
{
Expand All @@ -607,25 +641,25 @@
"outputs": [],
"source": [
"@app.get(\"/booly/\")\n",
"def booly(coming:bool=True): return 'Coming' if coming else 'Not coming'\n",
"def _(coming:bool=True): return 'Coming' if coming else 'Not coming'\n",
"\n",
"@app.get(\"/datie/\")\n",
"def datie(d:date): return d\n",
"def _(d:date): return d\n",
"\n",
"@app.get(\"/ua\")\n",
"async def ua(user_agent:str): return user_agent\n",
"async def _(user_agent:str): return user_agent\n",
"\n",
"@app.get(\"/hxtest\")\n",
"def hxtest(htmx): return htmx.request\n",
"def _(htmx): return htmx.request\n",
"\n",
"@app.get(\"/hxtest2\")\n",
"def hxtest(foo:HtmxHeaders, req): return foo.request\n",
"def _(foo:HtmxHeaders, req): return foo.request\n",
"\n",
"@app.get(\"/app\")\n",
"def apptest(app): return app.chk\n",
"def _(app): return app.chk\n",
"\n",
"@app.get(\"/app2\")\n",
"def apptest(foo:FastHTML): return foo.chk"
"def _(foo:FastHTML): return foo.chk"
]
},
{
Expand Down Expand Up @@ -721,13 +755,13 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Set to 2024-05-29 13:09:47.160097\n"
"Set to 2024-05-31 01:36:06.189385\n"
]
},
{
"data": {
"text/plain": [
"'Cookie was set at time 13:09:47.160097'"
"'Cookie was set at time 01:36:06.189385'"
]
},
"execution_count": null,
Expand Down
Loading

0 comments on commit dfc1391

Please sign in to comment.