python-fasthtml 0.13.2__tar.gz → 0.13.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 (39) hide show
  1. {python_fasthtml-0.13.2/python_fasthtml.egg-info → python_fasthtml-0.13.4}/PKG-INFO +2 -2
  2. python_fasthtml-0.13.4/fasthtml/__init__.py +2 -0
  3. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/_modidx.py +5 -1
  4. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/core.py +50 -15
  5. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/pyproject.toml +3 -1
  6. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4/python_fasthtml.egg-info}/PKG-INFO +2 -2
  7. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/python_fasthtml.egg-info/requires.txt +1 -1
  8. python_fasthtml-0.13.2/fasthtml/__init__.py +0 -2
  9. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/CONTRIBUTING.md +0 -0
  10. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/LICENSE +0 -0
  11. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/MANIFEST.in +0 -0
  12. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/README.md +0 -0
  13. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/authmw.py +0 -0
  14. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/basics.py +0 -0
  15. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/cli.py +0 -0
  16. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/common.py +0 -0
  17. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/components.py +0 -0
  18. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/components.pyi +0 -0
  19. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/core.pyi +0 -0
  20. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/fastapp.py +0 -0
  21. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/ft.py +0 -0
  22. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/js.py +0 -0
  23. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/jupyter.py +0 -0
  24. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/katex.js +0 -0
  25. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/live_reload.py +0 -0
  26. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/oauth.py +0 -0
  27. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/pico.py +0 -0
  28. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/starlette.py +0 -0
  29. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/stripe_otp.py +0 -0
  30. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/svg.py +0 -0
  31. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/toaster.py +0 -0
  32. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/xtend.py +0 -0
  33. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/fasthtml/xtend.pyi +0 -0
  34. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/python_fasthtml.egg-info/SOURCES.txt +0 -0
  35. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/python_fasthtml.egg-info/dependency_links.txt +0 -0
  36. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/python_fasthtml.egg-info/entry_points.txt +0 -0
  37. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/python_fasthtml.egg-info/top_level.txt +0 -0
  38. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/setup.cfg +0 -0
  39. {python_fasthtml-0.13.2 → python_fasthtml-0.13.4}/tests/test_toaster.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fasthtml
3
- Version: 0.13.2
3
+ Version: 0.13.4
4
4
  Summary: The fastest way to create an HTML app
5
5
  Author-email: Jeremy Howard and contributors <github@jhoward.fastmail.fm>
6
6
  License: Apache-2.0
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: fastcore>=1.12.16
18
+ Requires-Dist: fastcore>=1.12.41
19
19
  Requires-Dist: python-dateutil
20
20
  Requires-Dist: starlette~=1.0
21
21
  Requires-Dist: oauthlib
@@ -0,0 +1,2 @@
1
+ __version__ = "0.13.4"
2
+ from .core import *
@@ -40,6 +40,7 @@ d = { 'settings': { 'branch': 'main',
40
40
  'fasthtml.core.ApiReturn.__init__': ('api/core.html#apireturn.__init__', 'fasthtml/core.py'),
41
41
  'fasthtml.core.Beforeware': ('api/core.html#beforeware', 'fasthtml/core.py'),
42
42
  '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'),
43
44
  'fasthtml.core.Client': ('api/core.html#client', 'fasthtml/core.py'),
44
45
  'fasthtml.core.Client.__init__': ('api/core.html#client.__init__', 'fasthtml/core.py'),
45
46
  'fasthtml.core.Client._sync': ('api/core.html#client._sync', 'fasthtml/core.py'),
@@ -103,7 +104,6 @@ d = { 'settings': { 'branch': 'main',
103
104
  'fasthtml.core._LifespanCtx.__init__': ('api/core.html#_lifespanctx.__init__', 'fasthtml/core.py'),
104
105
  'fasthtml.core._add_ids': ('api/core.html#_add_ids', 'fasthtml/core.py'),
105
106
  'fasthtml.core._annotations': ('api/core.html#_annotations', 'fasthtml/core.py'),
106
- 'fasthtml.core._apply_ft': ('api/core.html#_apply_ft', 'fasthtml/core.py'),
107
107
  'fasthtml.core._canonical': ('api/core.html#_canonical', 'fasthtml/core.py'),
108
108
  'fasthtml.core._check_anno': ('api/core.html#_check_anno', 'fasthtml/core.py'),
109
109
  'fasthtml.core._find_p': ('api/core.html#_find_p', 'fasthtml/core.py'),
@@ -133,6 +133,7 @@ d = { 'settings': { 'branch': 'main',
133
133
  'fasthtml.core._wrap_ws': ('api/core.html#_wrap_ws', 'fasthtml/core.py'),
134
134
  'fasthtml.core._ws_endp': ('api/core.html#_ws_endp', 'fasthtml/core.py'),
135
135
  'fasthtml.core._xt_cts': ('api/core.html#_xt_cts', 'fasthtml/core.py'),
136
+ 'fasthtml.core.add_sig_param': ('api/core.html#add_sig_param', 'fasthtml/core.py'),
136
137
  'fasthtml.core.cookie': ('api/core.html#cookie', 'fasthtml/core.py'),
137
138
  'fasthtml.core.decode_uri': ('api/core.html#decode_uri', 'fasthtml/core.py'),
138
139
  'fasthtml.core.def_hdrs': ('api/core.html#def_hdrs', 'fasthtml/core.py'),
@@ -140,6 +141,9 @@ d = { 'settings': { 'branch': 'main',
140
141
  'fasthtml.core.flat_xt': ('api/core.html#flat_xt', 'fasthtml/core.py'),
141
142
  'fasthtml.core.form2dict': ('api/core.html#form2dict', 'fasthtml/core.py'),
142
143
  'fasthtml.core.get_key': ('api/core.html#get_key', 'fasthtml/core.py'),
144
+ 'fasthtml.core.into': ('api/core.html#into', 'fasthtml/core.py'),
145
+ 'fasthtml.core.into.__call__': ('api/core.html#into.__call__', 'fasthtml/core.py'),
146
+ 'fasthtml.core.into.__init__': ('api/core.html#into.__init__', 'fasthtml/core.py'),
143
147
  'fasthtml.core.is_full_page': ('api/core.html#is_full_page', 'fasthtml/core.py'),
144
148
  'fasthtml.core.nested_name': ('api/core.html#nested_name', 'fasthtml/core.py'),
145
149
  'fasthtml.core.noop_body': ('api/core.html#noop_body', 'fasthtml/core.py'),
@@ -9,7 +9,7 @@ __all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmx_resps', 'htmx_exts', 'htmxsrc',
9
9
  'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown', 'uri', 'decode_uri', 'flat_tuple', 'noop_body',
10
10
  'respond', 'is_full_page', 'Redirect', 'get_key', 'qp', 'def_hdrs', 'Lifespan', 'FastHTML', 'HostRoute',
11
11
  'nested_name', 'serve', 'Client', 'RouteFuncs', 'APIRouter', 'cookie', 'reg_re_param', 'StaticNoCache',
12
- 'MiddlewareBase', 'FtResponse', 'unqid']
12
+ 'add_sig_param', 'into', 'MiddlewareBase', 'FtResponse', 'unqid']
13
13
 
14
14
  # %% ../nbs/api/00_core.ipynb #23503b9e
15
15
  import json,uuid,inspect,types,asyncio,inspect,random,contextlib,httpx,itsdangerous,uvicorn
@@ -163,12 +163,15 @@ async def parse_form(req: Request) -> FormData:
163
163
  return await req.json() if ctype == 'application/json' else await req.form()
164
164
 
165
165
 
166
- # %% ../nbs/api/00_core.ipynb #089fe388
166
+ # %% ../nbs/api/00_core.ipynb #0caedd04
167
167
  async def _from_body(conn, p, data):
168
168
  "Create an instance of the annotated type from pre-parsed `data`"
169
169
  anno = p.annotation
170
170
  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))
172
175
  d = _annotations(anno)
173
176
  cargs = {k: _form_arg(k, v, d) for k, v in data.items() if not d or k in d}
174
177
  return anno(**cargs)
@@ -184,10 +187,12 @@ class ApiReturn:
184
187
  # %% ../nbs/api/00_core.ipynb #7cc39ba9
185
188
  class JSONResponse(JSONResponseOrig):
186
189
  "Same as starlette's version, but auto-stringifies non serializable types"
187
- def render(self, content: Any) -> bytes:
188
- res = json.dumps(content, ensure_ascii=False, allow_nan=False, indent=None, separators=(",", ":"), default=str)
190
+ def render(self, content:Any)->bytes:
191
+ def _default(o): return list(o) if is_listy(o) else str(o)
192
+ res = json.dumps(content, ensure_ascii=False, allow_nan=False, indent=None, separators=(",",":"), default=_default)
189
193
  return res.encode("utf-8")
190
194
 
195
+
191
196
  # %% ../nbs/api/00_core.ipynb #5fa96e3a
192
197
  async def _find_p(conn, data, hdrs, arg:str, p:Parameter):
193
198
  "In `data` find param named `arg` of type in `p` (`arg` is ignored for body types)"
@@ -207,7 +212,7 @@ async def _find_p(conn, data, hdrs, arg:str, p:Parameter):
207
212
  if anno is empty:
208
213
  if arg.lower()=='ws' or 'request'.startswith(arg.lower()): return conn
209
214
  if 'session'.startswith(arg.lower()): return conn.scope.get('session', {})
210
- if arg.lower()=='scope': return dict2obj(conn.scope)
215
+ if arg.lower()=='scope': return conn.scope
211
216
  if arg.lower()=='data': return data
212
217
  if arg.lower()=='htmx': return _get_htmx(hdrs)
213
218
  if arg.lower()=='app': return conn.scope['app']
@@ -260,6 +265,7 @@ def flat_xt(lst):
260
265
  # %% ../nbs/api/00_core.ipynb #aacff5ac
261
266
  class Beforeware:
262
267
  def __init__(self, f, skip=None): self.f,self.skip = f,skip or []
268
+ def __repr__(self): return f'Beforeware({self.f}, skip={self.skip})'
263
269
 
264
270
  # %% ../nbs/api/00_core.ipynb #78c3c357
265
271
  async def _handle(f, *args, **kwargs):
@@ -267,7 +273,7 @@ async def _handle(f, *args, **kwargs):
267
273
 
268
274
  # %% ../nbs/api/00_core.ipynb #ad0f0e87
269
275
  async def _wrap_ws(ws, data, params):
270
- hdrs = Headers({k.lower():v for k,v in data.pop('HEADERS', {}).items()})
276
+ hdrs = Headers({k.lower():v for k,v in data.pop('HEADERS', {}).items() if v is not None})
271
277
  return await _find_ps(ws, data, hdrs, params)
272
278
 
273
279
  # %% ../nbs/api/00_core.ipynb #dcc15129
@@ -365,16 +371,8 @@ def _find_targets(req, resp):
365
371
  t = resp.attrs.pop(k, None)
366
372
  if t: resp.attrs[v] = _url_for(req, t)
367
373
 
368
- def _apply_ft(o):
369
- "Apply FastTag transformation recursively to object `o`"
370
- if isinstance(o, tuple): o = tuple(_apply_ft(c) for c in o)
371
- if hasattr(o, '__ft__'): o = o.__ft__()
372
- if isinstance(o, FT): o.children = tuple(_apply_ft(c) for c in o.children)
373
- return o
374
-
375
374
  def _to_xml(req, resp, indent):
376
375
  "Convert response to XML string with target URL resolution"
377
- resp = _apply_ft(resp)
378
376
  _find_targets(req, resp)
379
377
  return to_xml(resp, indent=indent)
380
378
 
@@ -904,6 +902,43 @@ class StaticNoCache(StaticFiles):
904
902
  resp.headers.setdefault("Cache-Control", "no-cache")
905
903
  return resp
906
904
 
905
+ # %% ../nbs/api/00_core.ipynb #7189daf8
906
+ from functools import wraps
907
+ from inspect import signature, isawaitable
908
+
909
+ # %% ../nbs/api/00_core.ipynb #7eed23b7
910
+ def add_sig_param(f, name, typ=NoneType, kind=Parameter.KEYWORD_ONLY, default=Parameter.empty):
911
+ "Add a parameter to a function's signature"
912
+ sig = signature(f)
913
+ if name in sig.parameters: return f
914
+ kw = {} if default is Parameter.empty else {'default': default}
915
+ new_params = list(sig.parameters.values()) + [Parameter(name, kind, **kw)]
916
+ f.__signature__ = sig.replace(parameters=new_params)
917
+ f.__annotations__[name] = typ
918
+ return f
919
+
920
+ # %% ../nbs/api/00_core.ipynb #9e5a9e88
921
+ class into:
922
+ "Decorator to pass a route's return value into `func`, with keyword params added to the route signature"
923
+ def __init__(self, func):
924
+ self.func = func
925
+ self.params = {k:p for k,p in signature(func).parameters.items()
926
+ if p.kind not in (Parameter.VAR_POSITIONAL, Parameter.VAR_KEYWORD)}
927
+
928
+ def __call__(self, f):
929
+ @wraps(f)
930
+ async def _inner(*args, **kw):
931
+ extra = {k: kw.pop(k, None) for k in self.params}
932
+ res = f(*args, **kw)
933
+ if isawaitable(res): res = await res
934
+ res = self.func(*tuplify(res), **extra)
935
+ if isawaitable(res): res = await res
936
+ return res
937
+ for k,p in self.params.items():
938
+ anno = p.annotation if p.annotation is not Parameter.empty else NoneType
939
+ add_sig_param(_inner, k, anno, default=p.default)
940
+ return _inner
941
+
907
942
  # %% ../nbs/api/00_core.ipynb #1960d7ff
908
943
  class MiddlewareBase:
909
944
  async def __call__(self, scope, receive, send) -> None:
@@ -12,7 +12,7 @@ license = {text = "Apache-2.0"}
12
12
  authors = [{name = "Jeremy Howard and contributors", email = "github@jhoward.fastmail.fm"}]
13
13
  keywords = ['nbdev', 'jupyter', 'notebook', 'python']
14
14
  classifiers = ["Natural Language :: English", "Intended Audience :: Developers", "Development Status :: 3 - Alpha", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only"]
15
- dependencies = ['fastcore>=1.12.16', 'python-dateutil', 'starlette~=1.0', 'oauthlib', 'itsdangerous', 'uvicorn[standard]>=0.30', 'httpx', 'fastlite>=0.1.1', 'python-multipart', 'beautifulsoup4']
15
+ dependencies = ['fastcore>=1.12.41', 'python-dateutil', 'starlette~=1.0', 'oauthlib', 'itsdangerous', 'uvicorn[standard]>=0.30', 'httpx', 'fastlite>=0.1.1', 'python-multipart', 'beautifulsoup4']
16
16
 
17
17
  [project.urls]
18
18
  Repository = "https://github.com/AnswerDotAI/fasthtml"
@@ -36,6 +36,8 @@ version = {attr = "fasthtml.__version__"}
36
36
  include = ["fasthtml"]
37
37
 
38
38
  [tool.nbdev]
39
+ allowed_metadata_keys = ['solveit_dialog_mode', 'solveit_ver']
40
+ allowed_cell_metadata_keys = ["solveit_ai"]
39
41
  jupyter_hooks = true
40
42
  custom_sidebar = false
41
43
  lib_path = "fasthtml"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fasthtml
3
- Version: 0.13.2
3
+ Version: 0.13.4
4
4
  Summary: The fastest way to create an HTML app
5
5
  Author-email: Jeremy Howard and contributors <github@jhoward.fastmail.fm>
6
6
  License: Apache-2.0
@@ -15,7 +15,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
15
15
  Requires-Python: >=3.10
16
16
  Description-Content-Type: text/markdown
17
17
  License-File: LICENSE
18
- Requires-Dist: fastcore>=1.12.16
18
+ Requires-Dist: fastcore>=1.12.41
19
19
  Requires-Dist: python-dateutil
20
20
  Requires-Dist: starlette~=1.0
21
21
  Requires-Dist: oauthlib
@@ -1,4 +1,4 @@
1
- fastcore>=1.12.16
1
+ fastcore>=1.12.41
2
2
  python-dateutil
3
3
  starlette~=1.0
4
4
  oauthlib
@@ -1,2 +0,0 @@
1
- __version__ = "0.13.2"
2
- from .core import *