python-fasthtml 0.12.39__tar.gz → 0.12.41__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 (43) hide show
  1. {python_fasthtml-0.12.39/python_fasthtml.egg-info → python_fasthtml-0.12.41}/PKG-INFO +10 -25
  2. python_fasthtml-0.12.41/fasthtml/__init__.py +2 -0
  3. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/_modidx.py +8 -1
  4. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/cli.py +5 -5
  5. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/components.py +20 -20
  6. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/core.py +84 -82
  7. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/js.py +10 -10
  8. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/jupyter.py +17 -16
  9. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/oauth.py +65 -41
  10. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/pico.py +11 -11
  11. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/starlette.py +1 -1
  12. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/stripe_otp.py +18 -18
  13. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/svg.py +19 -19
  14. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/xtend.py +41 -41
  15. python_fasthtml-0.12.41/pyproject.toml +41 -0
  16. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41/python_fasthtml.egg-info}/PKG-INFO +10 -25
  17. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/python_fasthtml.egg-info/SOURCES.txt +0 -3
  18. python_fasthtml-0.12.39/fasthtml/__init__.py +0 -2
  19. python_fasthtml-0.12.39/pyproject.toml +0 -11
  20. python_fasthtml-0.12.39/python_fasthtml.egg-info/not-zip-safe +0 -1
  21. python_fasthtml-0.12.39/settings.ini +0 -43
  22. python_fasthtml-0.12.39/setup.py +0 -57
  23. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/CONTRIBUTING.md +0 -0
  24. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/LICENSE +0 -0
  25. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/MANIFEST.in +0 -0
  26. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/README.md +0 -0
  27. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/authmw.py +0 -0
  28. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/basics.py +0 -0
  29. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/common.py +0 -0
  30. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/components.pyi +0 -0
  31. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/core.pyi +0 -0
  32. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/fastapp.py +0 -0
  33. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/ft.py +0 -0
  34. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/katex.js +0 -0
  35. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/live_reload.py +0 -0
  36. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/toaster.py +0 -0
  37. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/fasthtml/xtend.pyi +0 -0
  38. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/python_fasthtml.egg-info/dependency_links.txt +0 -0
  39. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/python_fasthtml.egg-info/entry_points.txt +0 -0
  40. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/python_fasthtml.egg-info/requires.txt +0 -0
  41. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/python_fasthtml.egg-info/top_level.txt +0 -0
  42. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/setup.cfg +0 -0
  43. {python_fasthtml-0.12.39 → python_fasthtml-0.12.41}/tests/test_toaster.py +0 -0
@@ -1,20 +1,17 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fasthtml
3
- Version: 0.12.39
3
+ Version: 0.12.41
4
4
  Summary: The fastest way to create an HTML app
5
- Home-page: https://github.com/AnswerDotAI/fasthtml
6
- Author: Jeremy Howard and contributors
7
- Author-email: github@jhoward.fastmail.fm
8
- License: Apache Software License 2.0
9
- Keywords: nbdev jupyter notebook python
10
- Classifier: Development Status :: 4 - Beta
11
- Classifier: Intended Audience :: Developers
5
+ Author-email: Jeremy Howard and contributors <github@jhoward.fastmail.fm>
6
+ License: Apache-2.0
7
+ Project-URL: Repository, https://github.com/AnswerDotAI/fasthtml
8
+ Project-URL: Documentation, https://www.fastht.ml/docs/
9
+ Keywords: nbdev,jupyter,notebook,python
12
10
  Classifier: Natural Language :: English
13
- Classifier: Programming Language :: Python :: 3.10
14
- Classifier: Programming Language :: Python :: 3.11
15
- Classifier: Programming Language :: Python :: 3.12
16
- Classifier: Programming Language :: Python :: 3.13
17
- Classifier: License :: OSI Approved :: Apache Software License
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
18
15
  Requires-Python: >=3.10
19
16
  Description-Content-Type: text/markdown
20
17
  License-File: LICENSE
@@ -34,19 +31,7 @@ Requires-Dist: lxml; extra == "dev"
34
31
  Requires-Dist: pysymbol_llm; extra == "dev"
35
32
  Requires-Dist: monsterui; extra == "dev"
36
33
  Requires-Dist: PyJWT; extra == "dev"
37
- Dynamic: author
38
- Dynamic: author-email
39
- Dynamic: classifier
40
- Dynamic: description
41
- Dynamic: description-content-type
42
- Dynamic: home-page
43
- Dynamic: keywords
44
- Dynamic: license
45
34
  Dynamic: license-file
46
- Dynamic: provides-extra
47
- Dynamic: requires-dist
48
- Dynamic: requires-python
49
- Dynamic: summary
50
35
 
51
36
  # FastHTML
52
37
 
@@ -0,0 +1,2 @@
1
+ __version__ = "0.12.41"
2
+ from .core import *
@@ -1,7 +1,7 @@
1
1
  # Autogenerated by nbdev
2
2
 
3
3
  d = { 'settings': { 'branch': 'main',
4
- 'doc_baseurl': '/docs/',
4
+ 'doc_baseurl': '/docs',
5
5
  'doc_host': 'https://www.fastht.ml',
6
6
  'git_url': 'https://github.com/AnswerDotAI/fasthtml',
7
7
  'lib_path': 'fasthtml'},
@@ -203,10 +203,17 @@ d = { 'settings': { 'branch': 'main',
203
203
  'fasthtml.oauth._AppClient': ('api/oauth.html#_appclient', 'fasthtml/oauth.py'),
204
204
  'fasthtml.oauth._AppClient.__init__': ('api/oauth.html#_appclient.__init__', 'fasthtml/oauth.py'),
205
205
  'fasthtml.oauth._AppClient.get_info': ('api/oauth.html#_appclient.get_info', 'fasthtml/oauth.py'),
206
+ 'fasthtml.oauth._AppClient.get_info_async': ( 'api/oauth.html#_appclient.get_info_async',
207
+ 'fasthtml/oauth.py'),
206
208
  'fasthtml.oauth._AppClient.parse_response': ( 'api/oauth.html#_appclient.parse_response',
207
209
  'fasthtml/oauth.py'),
210
+ 'fasthtml.oauth._AppClient.parse_response_async': ( 'api/oauth.html#_appclient.parse_response_async',
211
+ 'fasthtml/oauth.py'),
208
212
  'fasthtml.oauth._AppClient.retr_id': ('api/oauth.html#_appclient.retr_id', 'fasthtml/oauth.py'),
209
213
  'fasthtml.oauth._AppClient.retr_info': ('api/oauth.html#_appclient.retr_info', 'fasthtml/oauth.py'),
214
+ 'fasthtml.oauth._AppClient.retr_info_async': ( 'api/oauth.html#_appclient.retr_info_async',
215
+ 'fasthtml/oauth.py'),
216
+ 'fasthtml.oauth._arun': ('api/oauth.html#_arun', 'fasthtml/oauth.py'),
210
217
  'fasthtml.oauth.get_host': ('api/oauth.html#get_host', 'fasthtml/oauth.py'),
211
218
  'fasthtml.oauth.load_creds': ('api/oauth.html#load_creds', 'fasthtml/oauth.py'),
212
219
  'fasthtml.oauth.redir_url': ('api/oauth.html#redir_url', 'fasthtml/oauth.py'),
@@ -1,16 +1,16 @@
1
1
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/09_cli.ipynb.
2
2
 
3
- # %% auto 0
3
+ # %% auto #0
4
4
  __all__ = ['railway_link', 'railway_deploy']
5
5
 
6
- # %% ../nbs/api/09_cli.ipynb
6
+ # %% ../nbs/api/09_cli.ipynb #acfbc502
7
7
  from fastcore.utils import *
8
8
  from fastcore.script import call_parse, bool_arg
9
9
  from subprocess import check_output, run
10
10
 
11
11
  import json
12
12
 
13
- # %% ../nbs/api/09_cli.ipynb
13
+ # %% ../nbs/api/09_cli.ipynb #11d71cfc
14
14
  @call_parse
15
15
  def railway_link():
16
16
  "Link the current directory to the current project's Railway service"
@@ -23,12 +23,12 @@ def railway_link():
23
23
  cmd = f"railway link -e {env} -p {prj} -s {svc}"
24
24
  res = check_output(cmd.split())
25
25
 
26
- # %% ../nbs/api/09_cli.ipynb
26
+ # %% ../nbs/api/09_cli.ipynb #586830f6
27
27
  def _run(a, **kw):
28
28
  print('#', ' '.join(a))
29
29
  run(a)
30
30
 
31
- # %% ../nbs/api/09_cli.ipynb
31
+ # %% ../nbs/api/09_cli.ipynb #b84fd5ff
32
32
  @call_parse
33
33
  def railway_deploy(
34
34
  name:str, # The project name to deploy
@@ -2,7 +2,7 @@
2
2
 
3
3
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/01_components.ipynb.
4
4
 
5
- # %% auto 0
5
+ # %% auto #0
6
6
  __all__ = ['named', 'html_attrs', 'hx_attrs', 'hx_evts', 'js_evts', 'hx_attrs_annotations', 'hx_evt_attrs', 'js_evt_attrs',
7
7
  'evt_attrs', 'attrmap_x', 'ft_html', 'ft_hx', 'File', 'show', 'fill_form', 'fill_dataclass', 'find_inputs',
8
8
  'html2ft', 'sse_message', 'A', 'Abbr', 'Address', 'Area', 'Article', 'Aside', 'Audio', 'B', 'Base', 'Bdi',
@@ -16,7 +16,7 @@ __all__ = ['named', 'html_attrs', 'hx_attrs', 'hx_evts', 'js_evts', 'hx_attrs_an
16
16
  'Tbody', 'Td', 'Template', 'Textarea', 'Tfoot', 'Th', 'Thead', 'Time', 'Title', 'Tr', 'Track', 'U', 'Ul',
17
17
  'Var', 'Video', 'Wbr']
18
18
 
19
- # %% ../nbs/api/01_components.ipynb
19
+ # %% ../nbs/api/01_components.ipynb #8e2d405b
20
20
  from dataclasses import dataclass, asdict, is_dataclass, make_dataclass, replace, astuple, MISSING
21
21
  from bs4 import BeautifulSoup, Comment
22
22
  from typing import Literal, Mapping, Optional
@@ -32,19 +32,19 @@ import types, json
32
32
  try: from IPython import display
33
33
  except ImportError: display=None
34
34
 
35
- # %% ../nbs/api/01_components.ipynb
35
+ # %% ../nbs/api/01_components.ipynb #dc101f0f
36
36
  @patch
37
37
  def __str__(self:FT): return self.id if self.id else to_xml(self, indent=False)
38
38
 
39
- # %% ../nbs/api/01_components.ipynb
39
+ # %% ../nbs/api/01_components.ipynb #a10500cb
40
40
  @patch
41
41
  def __radd__(self:FT, b): return f'{b}{self}'
42
42
 
43
- # %% ../nbs/api/01_components.ipynb
43
+ # %% ../nbs/api/01_components.ipynb #992319c5
44
44
  @patch
45
45
  def __add__(self:FT, b): return f'{self}{b}'
46
46
 
47
- # %% ../nbs/api/01_components.ipynb
47
+ # %% ../nbs/api/01_components.ipynb #0ff9acc3
48
48
  named = set('a button form frame iframe img input map meta object param select textarea'.split())
49
49
  html_attrs = 'id cls title style accesskey contenteditable dir draggable enterkeyhint hidden inert inputmode lang popover spellcheck tabindex translate'.split()
50
50
  hx_attrs = 'get post put delete patch trigger target swap swap_oob include select select_oob indicator push_url confirm disable replace_url vals disabled_elt ext headers history history_elt indicator inherit params preserve prompt replace_url request sync validate'
@@ -70,19 +70,19 @@ hx_evt_attrs = ['hx_on__'+camel2snake(o).replace(':','_') for o in hx_evts.split
70
70
  js_evt_attrs = ['hx_on_'+o for o in js_evts.split()]
71
71
  evt_attrs = js_evt_attrs+hx_evt_attrs
72
72
 
73
- # %% ../nbs/api/01_components.ipynb
73
+ # %% ../nbs/api/01_components.ipynb #f904f825
74
74
  def attrmap_x(o):
75
75
  if o.startswith('_at_'): o = '@'+o[4:]
76
76
  return attrmap(o)
77
77
 
78
- # %% ../nbs/api/01_components.ipynb
78
+ # %% ../nbs/api/01_components.ipynb #ee041be0
79
79
  fh_cfg['attrmap']=attrmap_x
80
80
  fh_cfg['valmap' ]=valmap
81
81
  fh_cfg['ft_cls' ]=FT
82
82
  fh_cfg['auto_id']=False
83
83
  fh_cfg['auto_name']=True
84
84
 
85
- # %% ../nbs/api/01_components.ipynb
85
+ # %% ../nbs/api/01_components.ipynb #c8ade6b4
86
86
  def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=None, valmap=None, ft_cls=None, **kwargs):
87
87
  ds,c = partition(c, risinstance(Mapping))
88
88
  for d in ds: kwargs = {**kwargs, **d}
@@ -97,7 +97,7 @@ def ft_html(tag: str, *c, id=None, cls=None, title=None, style=None, attrmap=Non
97
97
  if fh_cfg['auto_name'] and tag in named and id and 'name' not in kw: kw['name'] = kw['id']
98
98
  return ft_cls(tag,c,kw, void_=tag in voids)
99
99
 
100
- # %% ../nbs/api/01_components.ipynb
100
+ # %% ../nbs/api/01_components.ipynb #d5158b3d
101
101
  @use_kwargs(hx_attrs+evt_attrs, keep=True)
102
102
  def ft_hx(tag: str, *c, target_id=None, hx_vals=None, hx_target=None, **kwargs):
103
103
  if hx_vals: kwargs['hx_vals'] = json.dumps(hx_vals) if isinstance (hx_vals,dict) else hx_vals
@@ -105,7 +105,7 @@ def ft_hx(tag: str, *c, target_id=None, hx_vals=None, hx_target=None, **kwargs):
105
105
  if target_id: kwargs['hx_target'] = '#'+target_id
106
106
  return ft_html(tag, *c, **kwargs)
107
107
 
108
- # %% ../nbs/api/01_components.ipynb
108
+ # %% ../nbs/api/01_components.ipynb #ede9b44d
109
109
  _g = globals()
110
110
  _all_ = [
111
111
  'A', 'Abbr', 'Address', 'Area', 'Article', 'Aside', 'Audio', 'B', 'Base', 'Bdi', 'Bdo', 'Blockquote', 'Body', 'Br',
@@ -119,12 +119,12 @@ _all_ = [
119
119
  'Td', 'Template', 'Textarea', 'Tfoot', 'Th', 'Thead', 'Time', 'Title', 'Tr', 'Track', 'U', 'Ul', 'Var', 'Video', 'Wbr']
120
120
  for o in _all_: _g[o] = partial(ft_hx, o.lower())
121
121
 
122
- # %% ../nbs/api/01_components.ipynb
122
+ # %% ../nbs/api/01_components.ipynb #fab04fb3
123
123
  def File(fname):
124
124
  "Use the unescaped text in file `fname` directly"
125
125
  return NotStr(Path(fname).read_text())
126
126
 
127
- # %% ../nbs/api/01_components.ipynb
127
+ # %% ../nbs/api/01_components.ipynb #7861dfe6
128
128
  def show(ft, *rest, iframe=False, height='auto', style=None):
129
129
  "Renders FT Components into HTML within a Jupyter notebook."
130
130
  if isinstance(ft, str): ft = Safe(ft)
@@ -138,7 +138,7 @@ def show(ft, *rest, iframe=False, height='auto', style=None):
138
138
  warnings.simplefilter("ignore", UserWarning)
139
139
  display.display(display.HTML(res))
140
140
 
141
- # %% ../nbs/api/01_components.ipynb
141
+ # %% ../nbs/api/01_components.ipynb #1df362c7
142
142
  def _fill_item(item, obj):
143
143
  if not isinstance(item,FT): return item
144
144
  tag,cs,attr = item.list
@@ -168,20 +168,20 @@ def _fill_item(item, obj):
168
168
  if option: option.selected = '1'
169
169
  return FT(tag,cs,attr,void_=item.void_)
170
170
 
171
- # %% ../nbs/api/01_components.ipynb
171
+ # %% ../nbs/api/01_components.ipynb #f0c83f26
172
172
  def fill_form(form:FT, obj)->FT:
173
173
  "Fills named items in `form` using attributes in `obj`"
174
174
  if is_dataclass(obj): obj = asdict(obj)
175
175
  elif not isinstance(obj,dict): obj = obj.__dict__
176
176
  return _fill_item(form, obj)
177
177
 
178
- # %% ../nbs/api/01_components.ipynb
178
+ # %% ../nbs/api/01_components.ipynb #8b171490
179
179
  def fill_dataclass(src, dest):
180
180
  "Modifies dataclass in-place and returns it"
181
181
  for nm,val in asdict(src).items(): setattr(dest, nm, val)
182
182
  return dest
183
183
 
184
- # %% ../nbs/api/01_components.ipynb
184
+ # %% ../nbs/api/01_components.ipynb #c9594f70
185
185
  def find_inputs(e, tags='input', **kw):
186
186
  "Recursively find all elements in `e` with `tags` and attrs matching `kw`"
187
187
  if not isinstance(e, (list,tuple,FT)): return []
@@ -195,14 +195,14 @@ def find_inputs(e, tags='input', **kw):
195
195
  for o in cs: inputs += find_inputs(o, tags, **kw)
196
196
  return inputs
197
197
 
198
- # %% ../nbs/api/01_components.ipynb
198
+ # %% ../nbs/api/01_components.ipynb #1d8a28b1
199
199
  def __getattr__(tag):
200
200
  if tag.startswith('_') or tag[0].islower(): raise AttributeError
201
201
  tag = tag.replace("_", "-")
202
202
  def _f(*c, target_id=None, **kwargs): return ft_hx(tag, *c, target_id=target_id, **kwargs)
203
203
  return _f
204
204
 
205
- # %% ../nbs/api/01_components.ipynb
205
+ # %% ../nbs/api/01_components.ipynb #afb0f65c
206
206
  _re_h2x_attr_key = re.compile(r'^[A-Za-z_-][\w-]*$')
207
207
  def html2ft(html, attr1st=False):
208
208
  """Convert HTML to an `ft` expression"""
@@ -243,7 +243,7 @@ def html2ft(html, attr1st=False):
243
243
  for c in soup.find_all(string=risinstance(Comment)): c.extract()
244
244
  return _parse(soup, 1)
245
245
 
246
- # %% ../nbs/api/01_components.ipynb
246
+ # %% ../nbs/api/01_components.ipynb #c6203402
247
247
  def sse_message(elm, event='message'):
248
248
  "Convert element `elm` into a format suitable for SSE streaming"
249
249
  data = '\n'.join(f'data: {o}' for o in to_xml(elm).splitlines())