python-fasthtml 0.3.3__tar.gz → 0.3.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. {python-fasthtml-0.3.3/python_fasthtml.egg-info → python-fasthtml-0.3.4}/PKG-INFO +1 -1
  2. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/__init__.py +1 -1
  3. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/_modidx.py +9 -1
  4. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/core.py +67 -12
  5. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4/python_fasthtml.egg-info}/PKG-INFO +1 -1
  6. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/settings.ini +1 -1
  7. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/CONTRIBUTING.md +0 -0
  8. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/LICENSE +0 -0
  9. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/MANIFEST.in +0 -0
  10. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/README.md +0 -0
  11. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/authmw.py +0 -0
  12. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/cli.py +0 -0
  13. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/common.py +0 -0
  14. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/components.py +0 -0
  15. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/components.pyi +0 -0
  16. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/fastapp.py +0 -0
  17. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/ft.py +0 -0
  18. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/js.py +0 -0
  19. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/live_reload.py +0 -0
  20. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/oauth.py +0 -0
  21. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/starlette.py +0 -0
  22. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/svg.py +0 -0
  23. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/toaster.py +0 -0
  24. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/xtend.py +0 -0
  25. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/fasthtml/xtend.pyi +0 -0
  26. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/python_fasthtml.egg-info/SOURCES.txt +0 -0
  27. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/python_fasthtml.egg-info/dependency_links.txt +0 -0
  28. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/python_fasthtml.egg-info/entry_points.txt +0 -0
  29. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/python_fasthtml.egg-info/not-zip-safe +0 -0
  30. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/python_fasthtml.egg-info/requires.txt +0 -0
  31. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/python_fasthtml.egg-info/top_level.txt +0 -0
  32. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/setup.cfg +0 -0
  33. {python-fasthtml-0.3.3 → python-fasthtml-0.3.4}/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-fasthtml
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: The fastest way to create an HTML app
5
5
  Home-page: https://github.com/AnswerDotAI/fasthtml
6
6
  Author: Jeremy Howard
@@ -1,4 +1,4 @@
1
- __version__ = "0.3.3"
1
+ __version__ = "0.3.4"
2
2
  from .core import *
3
3
  from .authmw import *
4
4
  from .components import *
@@ -27,6 +27,8 @@ d = { 'settings': { 'branch': 'main',
27
27
  'fasthtml.core.FastHTML.__init__': ('api/core.html#fasthtml.__init__', 'fasthtml/core.py'),
28
28
  'fasthtml.core.FastHTML.route': ('api/core.html#fasthtml.route', 'fasthtml/core.py'),
29
29
  'fasthtml.core.FastHTML.ws': ('api/core.html#fasthtml.ws', 'fasthtml/core.py'),
30
+ 'fasthtml.core.HTTPConnection.url_path_for': ( 'api/core.html#httpconnection.url_path_for',
31
+ 'fasthtml/core.py'),
30
32
  'fasthtml.core.HtmxHeaders': ('api/core.html#htmxheaders', 'fasthtml/core.py'),
31
33
  'fasthtml.core.HtmxHeaders.__bool__': ('api/core.html#htmxheaders.__bool__', 'fasthtml/core.py'),
32
34
  'fasthtml.core.HttpHeader': ('api/core.html#httpheader', 'fasthtml/core.py'),
@@ -39,6 +41,7 @@ d = { 'settings': { 'branch': 'main',
39
41
  'fasthtml.core.RouterX.__init__': ('api/core.html#routerx.__init__', 'fasthtml/core.py'),
40
42
  'fasthtml.core.RouterX.add_route': ('api/core.html#routerx.add_route', 'fasthtml/core.py'),
41
43
  'fasthtml.core.RouterX.add_ws': ('api/core.html#routerx.add_ws', 'fasthtml/core.py'),
44
+ 'fasthtml.core.StringConvertor.to_string': ('api/core.html#stringconvertor.to_string', 'fasthtml/core.py'),
42
45
  'fasthtml.core.WS_RouteX': ('api/core.html#ws_routex', 'fasthtml/core.py'),
43
46
  'fasthtml.core.WS_RouteX.__init__': ('api/core.html#ws_routex.__init__', 'fasthtml/core.py'),
44
47
  'fasthtml.core._SessionMiddleware': ('api/core.html#_sessionmiddleware', 'fasthtml/core.py'),
@@ -46,6 +49,7 @@ d = { 'settings': { 'branch': 'main',
46
49
  'fasthtml/core.py'),
47
50
  'fasthtml.core._annotations': ('api/core.html#_annotations', 'fasthtml/core.py'),
48
51
  'fasthtml.core._find_p': ('api/core.html#_find_p', 'fasthtml/core.py'),
52
+ 'fasthtml.core._find_targets': ('api/core.html#_find_targets', 'fasthtml/core.py'),
49
53
  'fasthtml.core._find_wsp': ('api/core.html#_find_wsp', 'fasthtml/core.py'),
50
54
  'fasthtml.core._fix_anno': ('api/core.html#_fix_anno', 'fasthtml/core.py'),
51
55
  'fasthtml.core._form_arg': ('api/core.html#_form_arg', 'fasthtml/core.py'),
@@ -58,6 +62,8 @@ d = { 'settings': { 'branch': 'main',
58
62
  'fasthtml.core._resp': ('api/core.html#_resp', 'fasthtml/core.py'),
59
63
  'fasthtml.core._send_ws': ('api/core.html#_send_ws', 'fasthtml/core.py'),
60
64
  'fasthtml.core._sig': ('api/core.html#_sig', 'fasthtml/core.py'),
65
+ 'fasthtml.core._to_xml': ('api/core.html#_to_xml', 'fasthtml/core.py'),
66
+ 'fasthtml.core._url_for': ('api/core.html#_url_for', 'fasthtml/core.py'),
61
67
  'fasthtml.core._wrap_call': ('api/core.html#_wrap_call', 'fasthtml/core.py'),
62
68
  'fasthtml.core._wrap_ex': ('api/core.html#_wrap_ex', 'fasthtml/core.py'),
63
69
  'fasthtml.core._wrap_req': ('api/core.html#_wrap_req', 'fasthtml/core.py'),
@@ -66,6 +72,7 @@ d = { 'settings': { 'branch': 'main',
66
72
  'fasthtml.core._xt_resp': ('api/core.html#_xt_resp', 'fasthtml/core.py'),
67
73
  'fasthtml.core.cookie': ('api/core.html#cookie', 'fasthtml/core.py'),
68
74
  'fasthtml.core.date': ('api/core.html#date', 'fasthtml/core.py'),
75
+ 'fasthtml.core.decode_uri': ('api/core.html#decode_uri', 'fasthtml/core.py'),
69
76
  'fasthtml.core.flat_xt': ('api/core.html#flat_xt', 'fasthtml/core.py'),
70
77
  'fasthtml.core.form2dict': ('api/core.html#form2dict', 'fasthtml/core.py'),
71
78
  'fasthtml.core.get_key': ('api/core.html#get_key', 'fasthtml/core.py'),
@@ -73,7 +80,8 @@ d = { 'settings': { 'branch': 'main',
73
80
  'fasthtml.core.is_typeddict': ('api/core.html#is_typeddict', 'fasthtml/core.py'),
74
81
  'fasthtml.core.reg_re_param': ('api/core.html#reg_re_param', 'fasthtml/core.py'),
75
82
  'fasthtml.core.snake2hyphens': ('api/core.html#snake2hyphens', 'fasthtml/core.py'),
76
- 'fasthtml.core.str2int': ('api/core.html#str2int', 'fasthtml/core.py')},
83
+ 'fasthtml.core.str2int': ('api/core.html#str2int', 'fasthtml/core.py'),
84
+ 'fasthtml.core.uri': ('api/core.html#uri', 'fasthtml/core.py')},
77
85
  'fasthtml.fastapp': {},
78
86
  'fasthtml.ft': {},
79
87
  'fasthtml.js': {},
@@ -3,8 +3,8 @@
3
3
  # %% auto 0
4
4
  __all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmxscr', 'htmxwsscr', 'surrsrc', 'scopesrc', 'viewport', 'charset', 'all_meths',
5
5
  'is_typeddict', 'is_namedtuple', 'date', 'snake2hyphens', 'HtmxHeaders', 'str2int', 'HttpHeader',
6
- 'form2dict', 'flat_xt', 'Beforeware', 'WS_RouteX', 'RouteX', 'RouterX', 'get_key', 'FastHTML', 'cookie',
7
- 'reg_re_param', 'MiddlewareBase']
6
+ 'form2dict', 'flat_xt', 'Beforeware', 'WS_RouteX', 'uri', 'decode_uri', 'RouteX', 'RouterX', 'get_key',
7
+ 'FastHTML', 'cookie', 'reg_re_param', 'MiddlewareBase']
8
8
 
9
9
  # %% ../nbs/api/00_core.ipynb
10
10
  import json,uuid,inspect,types
@@ -20,9 +20,11 @@ from collections import namedtuple
20
20
  from inspect import isfunction,ismethod,Parameter,get_annotations
21
21
  from functools import wraps, partialmethod
22
22
  from http import cookies
23
+ from urllib.parse import urlencode, parse_qs, quote, unquote
23
24
  from copy import copy,deepcopy
24
25
  from warnings import warn
25
26
  from dateutil import parser as dtparse
27
+ from starlette.requests import HTTPConnection
26
28
 
27
29
  from .starlette import *
28
30
 
@@ -103,7 +105,7 @@ def _fix_anno(t):
103
105
  def _form_arg(k, v, d):
104
106
  "Get type by accessing key `k` from `d`, and use to cast `v`"
105
107
  if v is None: return
106
- if not isinstance(v, str): return v
108
+ if not isinstance(v, (str,list,tuple)): return v
107
109
  # This is the type we want to cast `v` to
108
110
  anno = d.get(k, None)
109
111
  if not anno: return v
@@ -258,6 +260,57 @@ class WS_RouteX(WebSocketRoute):
258
260
  name=None, middleware=None, hdrs=None, before=None):
259
261
  super().__init__(path, _ws_endp(recv, conn, disconn, hdrs, before), name=name, middleware=middleware)
260
262
 
263
+ # %% ../nbs/api/00_core.ipynb
264
+ def uri(_arg, **kwargs):
265
+ return f"{quote(_arg)}/{urlencode(kwargs, doseq=True)}"
266
+
267
+ # %% ../nbs/api/00_core.ipynb
268
+ def decode_uri(s):
269
+ arg,_,kw = s.partition('/')
270
+ return unquote(arg), {k:v[0] for k,v in parse_qs(kw).items()}
271
+
272
+ # %% ../nbs/api/00_core.ipynb
273
+ from starlette.convertors import StringConvertor
274
+
275
+ # %% ../nbs/api/00_core.ipynb
276
+ StringConvertor.regex = "[^/]*" # `+` replaced with `*`
277
+
278
+ @patch
279
+ def to_string(self:StringConvertor, value: str) -> str:
280
+ value = str(value)
281
+ assert "/" not in value, "May not contain path separators"
282
+ # assert value, "Must not be empty" # line removed due to errors
283
+ return value
284
+
285
+ # %% ../nbs/api/00_core.ipynb
286
+ @patch
287
+ def url_path_for(self:HTTPConnection, name: str, **path_params):
288
+ router: Router = self.scope["router"]
289
+ return router.url_path_for(name, **path_params)
290
+
291
+ # %% ../nbs/api/00_core.ipynb
292
+ _verbs = dict(get='hx-get', post='hx-post', put='hx-post', delete='hx-delete', patch='hx-patch', link='href')
293
+
294
+ def _url_for(req, t):
295
+ if callable(t): t = t.__routename__
296
+ kw = {}
297
+ if t.find('/')>-1 and (t.find('?')<0 or t.find('/')<t.find('?')): t,kw = decode_uri(t)
298
+ t,m,q = t.partition('?')
299
+ return f"{req.url_path_for(t, **kw)}{m}{q}"
300
+
301
+ def _find_targets(req, resp):
302
+ if isinstance(resp, tuple):
303
+ for o in resp: _find_targets(req, o)
304
+ if isinstance(resp, FT):
305
+ for o in resp.children: _find_targets(req, o)
306
+ for k,v in _verbs.items():
307
+ t = resp.attrs.pop(k, None)
308
+ if t: resp.attrs[v] = _url_for(req, t)
309
+
310
+ def _to_xml(req, resp, indent):
311
+ _find_targets(req, resp)
312
+ return to_xml(resp, indent)
313
+
261
314
  # %% ../nbs/api/00_core.ipynb
262
315
  def _xt_resp(req, resp):
263
316
  if not isinstance(resp, tuple): resp = (resp,)
@@ -269,7 +322,7 @@ def _xt_resp(req, resp):
269
322
  if resp and 'hx-request' not in req.headers and not any(getattr(o, 'tag', '')=='html' for o in resp):
270
323
  if not titles: titles = [Title('FastHTML page')]
271
324
  resp = Html(Head(*titles, *flat_xt(req.hdrs)), Body(bdy, *flat_xt(req.ftrs), **req.bodykw), **req.htmlkw)
272
- return HTMLResponse(to_xml(resp, indent=fh_cfg.indent), headers=http_hdrs)
325
+ return HTMLResponse(_to_xml(req, resp, indent=fh_cfg.indent), headers=http_hdrs)
273
326
 
274
327
  # %% ../nbs/api/00_core.ipynb
275
328
  def _resp(req, resp, cls=empty):
@@ -406,17 +459,19 @@ class FastHTML(Starlette):
406
459
  self.router = RouterX(routes, on_startup=on_startup, on_shutdown=on_shutdown, lifespan=lifespan,
407
460
  hdrs=hdrs, ftrs=ftrs, before=before, after=after, htmlkw=htmlkw, **bodykw)
408
461
 
409
- def route(self, path:str, methods=None, name=None, include_in_schema=True):
462
+ def route(self, path:str=None, methods=None, name=None, include_in_schema=True):
410
463
  "Add a route at `path`; the function name is the default method"
464
+ pathstr = None if callable(path) else path
411
465
  def f(func):
412
- n = name
413
- if methods:
414
- m = [methods] if isinstance(methods,str) else methods
415
- if not n: n = func.__name__
416
- else: m = [func.__name__]
417
- self.router.add_route(path, func, methods=m, name=n, include_in_schema=include_in_schema)
466
+ n,fn,p = name,func.__name__,pathstr
467
+ if methods: m = [methods] if isinstance(methods,str) else methods
468
+ else: m = [fn] if fn in _verbs else ['post']
469
+ if not n: n = fn
470
+ if not p: p = '/'+fn
471
+ self.router.add_route(p, func, methods=m, name=n, include_in_schema=include_in_schema)
472
+ func.__routename__ = n
418
473
  return func
419
- return f
474
+ return f(path) if callable(path) else f
420
475
 
421
476
  def ws(self, path:str, conn=None, disconn=None, name=None):
422
477
  def f(func):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-fasthtml
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: The fastest way to create an HTML app
5
5
  Home-page: https://github.com/AnswerDotAI/fasthtml
6
6
  Author: Jeremy Howard
@@ -1,7 +1,7 @@
1
1
  [DEFAULT]
2
2
  repo = fasthtml
3
3
  lib_name = fasthtml
4
- version = 0.3.3
4
+ version = 0.3.4
5
5
  min_python = 3.10
6
6
  license = apache2
7
7
  requirements = fastcore>=1.6.7 python-dateutil starlette>0.33 oauthlib itsdangerous uvicorn[standard]>=0.30 httpx fastlite>=0.0.6 python-multipart beautifulsoup4
File without changes