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.
- {python_fasthtml-0.14.2/python_fasthtml.egg-info → python_fasthtml-0.14.3}/PKG-INFO +2 -2
- python_fasthtml-0.14.3/fasthtml/__init__.py +2 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/_modidx.py +1 -1
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/core.py +20 -16
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/jupyter.py +20 -14
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/oauth.py +7 -7
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/pyproject.toml +1 -1
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3/python_fasthtml.egg-info}/PKG-INFO +2 -2
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/requires.txt +1 -1
- python_fasthtml-0.14.2/fasthtml/__init__.py +0 -2
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/CONTRIBUTING.md +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/LICENSE +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/MANIFEST.in +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/README.md +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/authmw.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/basics.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/cli.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/common.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/components.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/components.pyi +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/core.pyi +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/fastapp.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/ft.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/js.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/katex.js +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/live_reload.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/pico.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/starlette.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/stripe_otp.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/svg.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/toaster.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/xtend.py +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/fasthtml/xtend.pyi +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/SOURCES.txt +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/dependency_links.txt +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/entry_points.txt +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/top_level.txt +0 -0
- {python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/setup.cfg +0 -0
- {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.
|
|
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:
|
|
24
|
+
Requires-Dist: httpx2
|
|
25
25
|
Requires-Dist: fastlite>=0.1.1
|
|
26
26
|
Requires-Dist: python-multipart
|
|
27
27
|
Requires-Dist: beautifulsoup4
|
|
@@ -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',
|
|
9
|
-
'charset', 'cors_allow', 'iframe_scr', 'all_meths', 'devtools_loc', 'parsed_date',
|
|
10
|
-
'HtmxHeaders', 'HttpHeader', 'HtmxResponseHeaders', 'form2dict', 'parse_form', 'ApiReturn',
|
|
11
|
-
'flat_xt', 'Beforeware', 'EventStream', 'signal_shutdown', 'uri', 'decode_uri', 'flat_tuple',
|
|
12
|
-
'respond', 'is_full_page', 'Redirect', 'get_key', 'qp', 'def_hdrs', 'Lifespan', 'FastHTML',
|
|
13
|
-
'nested_name', 'serve', 'Client', 'RouteFuncs', 'APIRouter', 'cookie', 'reg_re_param',
|
|
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
|
|
822
|
-
self.cli =
|
|
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
|
|
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 =
|
|
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', '
|
|
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=
|
|
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:
|
|
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 #
|
|
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
|
-
|
|
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,
|
|
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 =
|
|
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
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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', '
|
|
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.
|
|
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:
|
|
24
|
+
Requires-Dist: httpx2
|
|
25
25
|
Requires-Dist: fastlite>=0.1.1
|
|
26
26
|
Requires-Dist: python-multipart
|
|
27
27
|
Requires-Dist: beautifulsoup4
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_fasthtml-0.14.2 → python_fasthtml-0.14.3}/python_fasthtml.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|