python-fasthtml 0.14.2__tar.gz → 0.14.3__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.14.2/python_fasthtml.egg-info → python_fasthtml-0.14.3}/PKG-INFO +2 -2
  2. python_fasthtml-0.14.3/fasthtml/__init__.py +2 -0
  3. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/_modidx.py +1 -1
  4. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/core.py +20 -16
  5. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/jupyter.py +20 -14
  6. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/oauth.py +7 -7
  7. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/pyproject.toml +1 -1
  8. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3/python_fasthtml.egg-info}/PKG-INFO +2 -2
  9. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/requires.txt +1 -1
  10. python_fasthtml-0.14.2/fasthtml/__init__.py +0 -2
  11. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/CONTRIBUTING.md +0 -0
  12. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/LICENSE +0 -0
  13. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/MANIFEST.in +0 -0
  14. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/README.md +0 -0
  15. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/authmw.py +0 -0
  16. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/basics.py +0 -0
  17. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/cli.py +0 -0
  18. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/common.py +0 -0
  19. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/components.py +0 -0
  20. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/components.pyi +0 -0
  21. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/core.pyi +0 -0
  22. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/fastapp.py +0 -0
  23. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/ft.py +0 -0
  24. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/js.py +0 -0
  25. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/katex.js +0 -0
  26. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/live_reload.py +0 -0
  27. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/pico.py +0 -0
  28. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/starlette.py +0 -0
  29. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/stripe_otp.py +0 -0
  30. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/svg.py +0 -0
  31. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/toaster.py +0 -0
  32. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/xtend.py +0 -0
  33. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/xtend.pyi +0 -0
  34. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/SOURCES.txt +0 -0
  35. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/dependency_links.txt +0 -0
  36. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/entry_points.txt +0 -0
  37. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/top_level.txt +0 -0
  38. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/setup.cfg +0 -0
  39. {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/tests/test_toaster.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fasthtml
3
- Version: 0.14.2
3
+ Version: 0.14.3
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
@@ -21,7 +21,7 @@ Requires-Dist: starlette>=1.0.1
21
21
  Requires-Dist: oauthlib
22
22
  Requires-Dist: itsdangerous
23
23
  Requires-Dist: uvicorn[standard]>=0.30
24
- Requires-Dist: httpx
24
+ Requires-Dist: httpx2
25
25
  Requires-Dist: fastlite>=0.1.1
26
26
  Requires-Dist: python-multipart
27
27
  Requires-Dist: beautifulsoup4
@@ -0,0 +1,2 @@
1
+ __version__ = "0.14.3"
2
+ from .core import *
@@ -176,7 +176,6 @@ d = { 'settings': { 'branch': 'main',
176
176
  'fasthtml.jupyter.JupyUvi._live_sse': ('api/jupyter.html#jupyuvi._live_sse', 'fasthtml/jupyter.py'),
177
177
  'fasthtml.jupyter.JupyUvi._setup_live': ('api/jupyter.html#jupyuvi._setup_live', 'fasthtml/jupyter.py'),
178
178
  'fasthtml.jupyter.JupyUvi.start': ('api/jupyter.html#jupyuvi.start', 'fasthtml/jupyter.py'),
179
- 'fasthtml.jupyter.JupyUvi.start_async': ('api/jupyter.html#jupyuvi.start_async', 'fasthtml/jupyter.py'),
180
179
  'fasthtml.jupyter.JupyUvi.stop': ('api/jupyter.html#jupyuvi.stop', 'fasthtml/jupyter.py'),
181
180
  'fasthtml.jupyter.JupyUviAsync': ('api/jupyter.html#jupyuviasync', 'fasthtml/jupyter.py'),
182
181
  'fasthtml.jupyter.JupyUviAsync.__init__': ( 'api/jupyter.html#jupyuviasync.__init__',
@@ -190,6 +189,7 @@ d = { 'settings': { 'branch': 'main',
190
189
  'fasthtml.jupyter.render_ft': ('api/jupyter.html#render_ft', 'fasthtml/jupyter.py'),
191
190
  'fasthtml.jupyter.show': ('api/jupyter.html#show', 'fasthtml/jupyter.py'),
192
191
  'fasthtml.jupyter.wait_port_free': ('api/jupyter.html#wait_port_free', 'fasthtml/jupyter.py'),
192
+ 'fasthtml.jupyter.wait_port_free_async': ('api/jupyter.html#wait_port_free_async', 'fasthtml/jupyter.py'),
193
193
  'fasthtml.jupyter.ws_client': ('api/jupyter.html#ws_client', 'fasthtml/jupyter.py')},
194
194
  'fasthtml.live_reload': {},
195
195
  'fasthtml.oauth': { 'fasthtml.oauth.AppleAppClient': ('api/oauth.html#appleappclient', 'fasthtml/oauth.py'),
@@ -5,13 +5,13 @@ Docs: https://www.fastht.ml/docsapi/core.html.md"""
5
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/00_core.ipynb.
6
6
 
7
7
  # %% auto #0
8
- __all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmx_resps', 'htmx_exts', 'htmxsrc', 'fhjsscr', 'surrsrc', 'scopesrc', 'viewport',
9
- 'charset', 'cors_allow', 'iframe_scr', 'all_meths', 'devtools_loc', 'parsed_date', 'snake2hyphens',
10
- 'HtmxHeaders', 'HttpHeader', 'HtmxResponseHeaders', 'form2dict', 'parse_form', 'ApiReturn', 'JSONResponse',
11
- 'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown', 'uri', 'decode_uri', 'flat_tuple', 'noop_body',
12
- 'respond', 'is_full_page', 'Redirect', 'get_key', 'qp', 'def_hdrs', 'Lifespan', 'FastHTML', 'HostRoute',
13
- 'nested_name', 'serve', 'Client', 'RouteFuncs', 'APIRouter', 'cookie', 'reg_re_param', 'StaticNoCache',
14
- 'add_sig_param', 'into', 'MiddlewareBase', 'FtResponse', 'unqid']
8
+ __all__ = ['empty', 'htmx_hdrs', 'fh_cfg', 'htmx_resps', 'DEF_MAXPART', 'htmx_exts', 'htmxsrc', 'fhjsscr', 'surrsrc', 'scopesrc',
9
+ 'viewport', 'charset', 'cors_allow', 'iframe_scr', 'all_meths', 'devtools_loc', 'parsed_date',
10
+ 'snake2hyphens', 'HtmxHeaders', 'HttpHeader', 'HtmxResponseHeaders', 'form2dict', 'parse_form', 'ApiReturn',
11
+ 'JSONResponse', 'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown', 'uri', 'decode_uri', 'flat_tuple',
12
+ 'noop_body', 'respond', 'is_full_page', 'Redirect', 'get_key', 'qp', 'def_hdrs', 'Lifespan', 'FastHTML',
13
+ 'HostRoute', 'nested_name', 'serve', 'Client', 'RouteFuncs', 'APIRouter', 'cookie', 'reg_re_param',
14
+ 'StaticNoCache', 'add_sig_param', 'into', 'MiddlewareBase', 'FtResponse', 'unqid']
15
15
 
16
16
  # %% ../nbs/api/00_core.ipynb #23503b9e
17
17
  import json,uuid,inspect,types,asyncio,inspect,random,contextlib,itsdangerous
@@ -152,18 +152,21 @@ def form2dict(form: FormData) -> dict:
152
152
  if isinstance(form, dict): return form
153
153
  return {k: _formitem(form, k) for k in form}
154
154
 
155
+ # %% ../nbs/api/00_core.ipynb #8899bc0a
156
+ DEF_MAXPART = 100*1024*1024
157
+
155
158
  # %% ../nbs/api/00_core.ipynb #42c9cea0
156
159
  async def parse_form(req: Request) -> FormData:
157
160
  "Starlette errors on empty multipart forms, so this checks for that situation"
158
161
  ctype = req.headers.get("Content-Type", "")
162
+ maxpart = getattr(req, "max_part_size", DEF_MAXPART)
159
163
  if ctype.startswith("multipart/form-data"):
160
164
  try: boundary = ctype.split("boundary=")[1].strip()
161
165
  except IndexError: raise HTTPException(400, "Invalid form-data: no boundary")
162
166
  if int(req.headers.get("Content-Length", "0")) <= len(boundary) + 6: return FormData()
163
- return await req.form()
167
+ return await req.form(max_part_size=maxpart)
164
168
  await req.body() # Cache body for non-multipart request types
165
- return await req.json() if ctype == 'application/json' else await req.form()
166
-
169
+ return await req.json() if ctype == 'application/json' else await req.form(max_part_size=maxpart)
167
170
 
168
171
  # %% ../nbs/api/00_core.ipynb #0caedd04
169
172
  async def _from_body(conn, p, data):
@@ -602,7 +605,7 @@ class FastHTML(Starlette):
602
605
  before=None, after=None, surreal=True, htmx=True, default_hdrs=True, sess_cls=SessionMiddleware,
603
606
  secret_key=None, session_cookie='session_', max_age=365*24*3600, sess_path='/',
604
607
  same_site='lax', sess_https_only=False, sess_domain=None, key_fname='.sesskey',
605
- body_wrap=noop_body, htmlkw=None, nb_hdrs=False, canonical=True, **bodykw):
608
+ body_wrap=noop_body, htmlkw=None, nb_hdrs=False, canonical=True, max_part_size=DEF_MAXPART, **bodykw):
606
609
  middleware,before,after = map(_list, (middleware,before,after))
607
610
  self.title,self.canonical,self.session_cookie,self.key_fname = title,canonical,session_cookie,key_fname
608
611
  hdrs,ftrs,exts = map(listify, (hdrs,ftrs,exts))
@@ -617,7 +620,7 @@ class FastHTML(Starlette):
617
620
  middleware.append(cors_allow)
618
621
  self.lifespan = Lifespan(on_startup, on_shutdown, lifespan)
619
622
  self.hdrs,self.ftrs = hdrs,ftrs
620
- self.body_wrap,self.before,self.after,self.htmlkw,self.bodykw = body_wrap,before,after,htmlkw,bodykw
623
+ self.body_wrap,self.before,self.after,self.htmlkw,self.bodykw,self.max_part_size = body_wrap,before,after,htmlkw,bodykw,max_part_size
621
624
  self.secret_key = get_key(secret_key, key_fname)
622
625
  if sess_cls:
623
626
  sess = Middleware(sess_cls, secret_key=self.secret_key,session_cookie=session_cookie,
@@ -675,6 +678,7 @@ def _endp(self:FastHTML, f, body_wrap, before:Optional[Callable|tuple]=None):
675
678
  async def _f(req):
676
679
  resp = None
677
680
  req.injects = []
681
+ req.max_part_size = self.max_part_size
678
682
  req.hdrs,req.ftrs,req.htmlkw,req.bodykw = map(deepcopy, (self.hdrs,self.ftrs,self.htmlkw,self.bodykw))
679
683
  req.hdrs,req.ftrs = listify(req.hdrs),listify(req.ftrs)
680
684
  for b in self.before:
@@ -818,8 +822,8 @@ def serve(
818
822
  class Client:
819
823
  "A simple httpx ASGI client that doesn't require `async`"
820
824
  def __init__(self, app, url="http://testserver"):
821
- import httpx
822
- self.cli = httpx.AsyncClient(transport=httpx.ASGITransport(app), base_url=url)
825
+ import httpx2
826
+ self.cli = httpx2.AsyncClient(transport=httpx2.ASGITransport(app), base_url=url)
823
827
 
824
828
  def _sync(self, method, url, **kwargs):
825
829
  async def _request(): return await self.cli.request(method, url, **kwargs)
@@ -1028,11 +1032,11 @@ def devtools_json(self:FastHTML, path=None, uuid=None):
1028
1032
  @patch
1029
1033
  def get_client(self:FastHTML, asink=False, **kw):
1030
1034
  "Get an httpx client with session cookes set from `**kw`"
1031
- import httpx
1035
+ import httpx2
1032
1036
  signer = itsdangerous.TimestampSigner(self.secret_key)
1033
1037
  data = b64encode(dumps(kw).encode())
1034
1038
  data = signer.sign(data)
1035
- client = httpx.AsyncClient() if asink else httpx.Client()
1039
+ client = httpx2.AsyncClient() if asink else httpx2.Client()
1036
1040
  client.cookies.update({self.session_cookie: data.decode()})
1037
1041
  return client
1038
1042
 
@@ -5,8 +5,8 @@ Docs: https://www.fastht.ml/docsapi/jupyter.html.md"""
5
5
  # AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api/06_jupyter.ipynb.
6
6
 
7
7
  # %% auto #0
8
- __all__ = ['nb_serve', 'nb_serve_async', 'is_port_free', 'wait_port_free', 'show', 'render_ft', 'htmx_config_port', 'JupyUvi',
9
- 'JupyUviAsync', 'HTMX', 'ws_client']
8
+ __all__ = ['nb_serve', 'nb_serve_async', 'is_port_free', 'wait_port_free', 'wait_port_free_async', 'show', 'render_ft',
9
+ 'htmx_config_port', 'JupyUvi', 'JupyUviAsync', 'HTMX', 'ws_client']
10
10
 
11
11
  # %% ../nbs/api/06_jupyter.ipynb #2c69d9d0
12
12
  import asyncio, socket, time, uvicorn
@@ -38,23 +38,31 @@ async def nb_serve_async(app, log_level="error", port=8000, host='0.0.0.0', **kw
38
38
 
39
39
  # %% ../nbs/api/06_jupyter.ipynb #508917bc
40
40
  def is_port_free(port, host='localhost'):
41
- "Check if `port` is free on `host`"
42
41
  sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
42
+ sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
43
43
  try:
44
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
45
44
  sock.bind((host, port))
45
+ sock.listen(1)
46
46
  return True
47
47
  except OSError: return False
48
48
  finally: sock.close()
49
49
 
50
50
  # %% ../nbs/api/06_jupyter.ipynb #1779cb76
51
- def wait_port_free(port, host='localhost', max_wait=3):
51
+ def wait_port_free(port, host='localhost', max_wait=20):
52
52
  "Wait for `port` to be free on `host`"
53
53
  start_time = time.time()
54
- while not is_port_free(port):
55
- if time.time() - start_time>max_wait: return print(f"Timeout")
54
+ while not is_port_free(port, host):
55
+ if time.time() - start_time > max_wait: raise TimeoutError(f"Port {host}:{port} not free after {max_wait}s")
56
56
  time.sleep(0.1)
57
57
 
58
+ async def wait_port_free_async(port, host='localhost', max_wait=20):
59
+ "Async wait for `port` to be free on `host`"
60
+ start_time = time.time()
61
+ while not is_port_free(port, host):
62
+ if time.time() - start_time > max_wait: raise TimeoutError(f"Port {host}:{port} not free after {max_wait}s")
63
+ await asyncio.sleep(0.1)
64
+
65
+
58
66
  # %% ../nbs/api/06_jupyter.ipynb #654b36bb
59
67
  @delegates(_show)
60
68
  def show(*s, **kwargs):
@@ -96,12 +104,9 @@ class JupyUvi:
96
104
  def start(self):
97
105
  self.server = nb_serve(self.app, log_level=self.log_level, host=self.host, port=self.port,daemon=self.daemon, **self.kwargs)
98
106
 
99
- async def start_async(self):
100
- self.server = await nb_serve_async(self.app, log_level=self.log_level, host=self.host, port=self.port, **self.kwargs)
101
-
102
107
  def stop(self):
103
108
  self.server.should_exit = True
104
- wait_port_free(self.port)
109
+ wait_port_free(self.port, self.host)
105
110
 
106
111
  def _setup_live(self, app):
107
112
  rt = self.live_rt or '/_lr'
@@ -119,7 +124,7 @@ class JupyUvi:
119
124
  ver = self._live_ver
120
125
  yield 'data: reload\n\n'
121
126
 
122
- # %% ../nbs/api/06_jupyter.ipynb #9134035e
127
+ # %% ../nbs/api/06_jupyter.ipynb #f6316c73
123
128
  class JupyUviAsync(JupyUvi):
124
129
  "Start and stop an async Jupyter compatible uvicorn server with ASGI `app` on `port` with `log_level`"
125
130
  def __init__(self, app, log_level="error", host='0.0.0.0', port=8000, **kwargs):
@@ -128,9 +133,10 @@ class JupyUviAsync(JupyUvi):
128
133
  async def start(self):
129
134
  self.server = await nb_serve_async(self.app, log_level=self.log_level, host=self.host, port=self.port, **self.kwargs)
130
135
 
131
- def stop(self):
136
+ async def stop(self):
132
137
  self.server.should_exit = True
133
- wait_port_free(self.port)
138
+ await wait_port_free_async(self.port, self.host)
139
+
134
140
 
135
141
  # %% ../nbs/api/06_jupyter.ipynb #a448e420
136
142
  from starlette.testclient import TestClient
@@ -12,7 +12,7 @@ __all__ = ['log', 'http_patterns', 'GoogleAppClient', 'GitHubAppClient', 'Huggin
12
12
  from .common import *
13
13
  from oauthlib.oauth2 import WebApplicationClient
14
14
  from urllib.parse import urlparse, urlencode, parse_qs, quote, unquote
15
- import secrets, httpx, time, asyncio, logging
15
+ import secrets, httpx2, time, asyncio, logging
16
16
 
17
17
  # %% ../nbs/api/08_oauth.ipynb #44aa4a88
18
18
  log = logging.getLogger(__name__)
@@ -95,7 +95,7 @@ class DiscordAppClient(_AppClient):
95
95
  headers = {'Content-Type': 'application/x-www-form-urlencoded'}
96
96
  data = dict(grant_type='authorization_code', code=code)
97
97
  if redirect_uri: data['redirect_uri'] = redirect_uri
98
- r = httpx.post(self.token_url, data=data, headers=headers, auth=(self.client_id, self.client_secret)
98
+ r = httpx2.post(self.token_url, data=data, headers=headers, auth=(self.client_id, self.client_secret)
99
99
  ).raise_for_status()
100
100
  self.parse_request_body_response(r.text)
101
101
 
@@ -109,7 +109,7 @@ class Auth0AppClient(_AppClient):
109
109
  super().__init__(client_id, client_secret, code=code, scope=scope, redirect_uri=redirect_uri, **kwargs)
110
110
 
111
111
  def _fetch_openid_config(self):
112
- return httpx.get(f"https://{self.domain}/.well-known/openid-configuration").raise_for_status().json()
112
+ return httpx2.get(f"https://{self.domain}/.well-known/openid-configuration").raise_for_status().json()
113
113
 
114
114
  def login_link(self, req):
115
115
  d = dict(response_type="code", client_id=self.client_id, scope=self.scope, redirect_uri=redir_url(req, self.redirect_uri))
@@ -169,7 +169,7 @@ def parse_response(self:_AppClient, code, redirect_uri):
169
169
  "Get the token from the oauth2 server response"
170
170
  payload = dict(code=code, redirect_uri=redirect_uri, client_id=self.client_id,
171
171
  client_secret=self.client_secret, grant_type='authorization_code')
172
- r = httpx.post(self.token_url, data=payload).raise_for_status()
172
+ r = httpx2.post(self.token_url, data=payload).raise_for_status()
173
173
  self.parse_request_body_response(r.text)
174
174
 
175
175
  @patch
@@ -177,7 +177,7 @@ def get_info(self:_AppClient, token=None):
177
177
  "Get the info for authenticated user"
178
178
  if not token: token = self.token["access_token"]
179
179
  headers = {'Authorization': f'Bearer {token}'}
180
- return httpx.get(self.info_url, headers=headers).json()
180
+ return httpx2.get(self.info_url, headers=headers).json()
181
181
 
182
182
  @patch
183
183
  def retr_info(self:_AppClient, code, redirect_uri):
@@ -192,7 +192,7 @@ async def parse_response_async(self:_AppClient, code, redirect_uri):
192
192
  payload = dict(code=code, redirect_uri=redirect_uri, client_id=self.client_id,
193
193
  client_secret=self.client_secret, grant_type='authorization_code')
194
194
  log.debug(f"OAuth token request: redirect_uri={redirect_uri}, code={code[:20]}...")
195
- async with httpx.AsyncClient() as c:
195
+ async with httpx2.AsyncClient() as c:
196
196
  r = (await c.post(self.token_url, data=payload))
197
197
  log.debug(f"OAuth response: {r.status_code} - {r.text}")
198
198
  r.raise_for_status()
@@ -203,7 +203,7 @@ async def get_info_async(self:_AppClient, token=None):
203
203
  "Get the info for authenticated user"
204
204
  if not token: token = self.token["access_token"]
205
205
  headers = {'Authorization': f'Bearer {token}'}
206
- async with httpx.AsyncClient() as c:
206
+ async with httpx2.AsyncClient() as c:
207
207
  return (await c.get(self.info_url, headers=headers)).raise_for_status().json()
208
208
 
209
209
  @patch
@@ -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.45', 'python-dateutil', 'starlette>=1.0.1', 'oauthlib', 'itsdangerous', 'uvicorn[standard]>=0.30', 'httpx', 'fastlite>=0.1.1', 'python-multipart', 'beautifulsoup4']
15
+ dependencies = ['fastcore>=1.12.45', 'python-dateutil', 'starlette>=1.0.1', 'oauthlib', 'itsdangerous', 'uvicorn[standard]>=0.30', 'httpx2', 'fastlite>=0.1.1', 'python-multipart', 'beautifulsoup4']
16
16
 
17
17
  [project.urls]
18
18
  Repository = "https://github.com/AnswerDotAI/fasthtml"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-fasthtml
3
- Version: 0.14.2
3
+ Version: 0.14.3
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
@@ -21,7 +21,7 @@ Requires-Dist: starlette>=1.0.1
21
21
  Requires-Dist: oauthlib
22
22
  Requires-Dist: itsdangerous
23
23
  Requires-Dist: uvicorn[standard]>=0.30
24
- Requires-Dist: httpx
24
+ Requires-Dist: httpx2
25
25
  Requires-Dist: fastlite>=0.1.1
26
26
  Requires-Dist: python-multipart
27
27
  Requires-Dist: beautifulsoup4
@@ -4,7 +4,7 @@ starlette>=1.0.1
4
4
  oauthlib
5
5
  itsdangerous
6
6
  uvicorn[standard]>=0.30
7
- httpx
7
+ httpx2
8
8
  fastlite>=0.1.1
9
9
  python-multipart
10
10
  beautifulsoup4
@@ -1,2 +0,0 @@
1
- __version__ = "0.14.2"
2
- from .core import *