Spaces:
Sleeping
Sleeping
| # Jupyter compatibility | |
| <!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> | |
| ``` python | |
| from httpx import get, AsyncClient | |
| ``` | |
| ## Helper functions | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L21" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### nb_serve | |
| > nb_serve (app, log_level='error', port=8000, host='0.0.0.0', **kwargs) | |
| *Start a Jupyter compatible uvicorn server with ASGI `app` on `port` | |
| with `log_level`* | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L31" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### nb_serve_async | |
| > nb_serve_async (app, log_level='error', port=8000, host='0.0.0.0', | |
| > **kwargs) | |
| *Async version of | |
| [`nb_serve`](https://www.fastht.ml/docs/api/jupyter.html#nb_serve)* | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L39" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### is_port_free | |
| > is_port_free (port, host='localhost') | |
| *Check if `port` is free on `host`* | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L50" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### wait_port_free | |
| > wait_port_free (port, host='localhost', max_wait=3) | |
| *Wait for `port` to be free on `host`* | |
| ## Using FastHTML in Jupyter | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/components.py#L128" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### show | |
| > show (*s, iframe=False, height='auto', style=None) | |
| *Same as fasthtml.components.show, but also adds `htmx.process()`* | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L65" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### render_ft | |
| > render_ft () | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L70" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### htmx_config_port | |
| > htmx_config_port (port=8000) | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L81" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### JupyUvi | |
| > JupyUvi (app, log_level='error', host='0.0.0.0', port=8000, start=True, | |
| > **kwargs) | |
| *Start and stop a Jupyter compatible uvicorn server with ASGI `app` on | |
| `port` with `log_level`* | |
| Creating an object of this class also starts the Uvicorn server. It runs | |
| in a separate thread, so you can use normal HTTP client functions in a | |
| notebook. | |
| ``` python | |
| app = FastHTML() | |
| rt = app.route | |
| @app.route | |
| def index(): return 'hi' | |
| port = 8000 | |
| server = JupyUvi(app, port=port) | |
| ``` | |
| <script> | |
| document.body.addEventListener('htmx:configRequest', (event) => { | |
| if(event.detail.path.includes('://')) return; | |
| htmx.config.selfRequestsOnly=false; | |
| event.detail.path = `${location.protocol}//${location.hostname}:8000${event.detail.path}`; | |
| }); | |
| </script> | |
| ``` python | |
| get(f'http://localhost:{port}').text | |
| ``` | |
| 'hi' | |
| You can stop the server, modify routes, and start the server again | |
| without restarting the notebook or recreating the server or application. | |
| ``` python | |
| server.stop() | |
| ``` | |
| ``` python | |
| app = FastHTML() | |
| rt = app.route | |
| @app.route | |
| async def index(): return 'hi' | |
| server = JupyUvi(app, port=port, start=False) | |
| await server.start_async() | |
| ``` | |
| <script> | |
| document.body.addEventListener('htmx:configRequest', (event) => { | |
| if(event.detail.path.includes('://')) return; | |
| htmx.config.selfRequestsOnly=false; | |
| event.detail.path = `${location.protocol}//${location.hostname}:8000${event.detail.path}`; | |
| }); | |
| </script> | |
| ``` python | |
| print((await AsyncClient().get(f'http://localhost:{port}')).text) | |
| ``` | |
| hi | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L101" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### JupyUviAsync | |
| > JupyUviAsync (app, log_level='error', host='0.0.0.0', port=8000, | |
| > **kwargs) | |
| *Start and stop an async Jupyter compatible uvicorn server with ASGI | |
| `app` on `port` with `log_level`* | |
| ``` python | |
| server = JupyUviAsync(app, port=port) | |
| await server.start() | |
| ``` | |
| <script> | |
| document.body.addEventListener('htmx:configRequest', (event) => { | |
| if(event.detail.path.includes('://')) return; | |
| htmx.config.selfRequestsOnly=false; | |
| event.detail.path = `${location.protocol}//${location.hostname}:8000${event.detail.path}`; | |
| }); | |
| </script> | |
| ``` python | |
| async with AsyncClient() as client: | |
| r = await client.get(f'http://localhost:{port}') | |
| print(r.text) | |
| ``` | |
| hi | |
| ``` python | |
| server.stop() | |
| ``` | |
| ### Using a notebook as a web app | |
| You can also run an HTMX web app directly in a notebook. To make this | |
| work, you have to add the default FastHTML headers to the DOM of the | |
| notebook with `show(*def_hdrs())`. Additionally, you might find it | |
| convenient to use *auto_id* mode, in which the ID of an `FT` object is | |
| automatically generated if not provided. | |
| ``` python | |
| fh_cfg['auto_id' ]=True | |
| ``` | |
| After importing `fasthtml.jupyter` and calling | |
| [`render_ft()`](https://www.fastht.ml/docs/api/jupyter.html#render_ft), | |
| FT components render directly in the notebook. | |
| ``` python | |
| show(*def_hdrs()) | |
| render_ft() | |
| ``` | |
| </script><script src="https://cdn.jsdelivr.net/gh/answerdotai/fasthtml-js@1.0.12/fasthtml.js"></script><script src="https://cdn.jsdelivr.net/gh/answerdotai/surreal@main/surreal.js"></script><script src="https://cdn.jsdelivr.net/gh/gnat/css-scope-inline@main/script.js"></script><script id="_7KKmEIAnRE_-M4c4Lf5dJg">if (window.htmx) htmx.process(document.body)</script> | |
| ``` python | |
| (c := Div('Cogito ergo sum')) | |
| ``` | |
| <div id="_NNvXojeGS-eH1SZLG-pE4Q"> | |
| <div id="_vzHRxQNEQiaSQnLdUFq2Mg"> | |
| Cogito ergo sum | |
| </div> | |
| <script id="_SN7to4-bQ5O09J6vs2UvNA">if (window.htmx) htmx.process(document.body)</script> | |
| </div> | |
| Handlers are written just like a regular web app: | |
| ``` python | |
| server = JupyUvi(app, port=port) | |
| ``` | |
| <script> | |
| document.body.addEventListener('htmx:configRequest', (event) => { | |
| if(event.detail.path.includes('://')) return; | |
| htmx.config.selfRequestsOnly=false; | |
| event.detail.path = `${location.protocol}//${location.hostname}:8000${event.detail.path}`; | |
| }); | |
| </script> | |
| ``` python | |
| @rt | |
| def hoho(): return P('loaded!'), Div('hee hee', id=c, hx_swap_oob='true') | |
| ``` | |
| All the usual `hx_*` attributes can be used: | |
| ``` python | |
| P('not loaded', hx_get=hoho, hx_trigger='load') | |
| ``` | |
| not loaded | |
| if (window.htmx) htmx.process(document.body)</script> | |
| </div> | |
| FT components can be used directly both as `id` values and as | |
| `hx_target` values. | |
| ``` python | |
| (c := Div('')) | |
| ``` | |
| <div id="_C4mtvDiLQPyjFBL_N9guOQ"> | |
| <div id="_dazDkLiNRi_5IRjKxnDApQ"> | |
| </div> | |
| <script id="_wBaWxkrPTeyFjAjoTOAjaw">if (window.htmx) htmx.process(document.body)</script> | |
| </div> | |
| ``` python | |
| @rt | |
| def foo(): return Div('foo bar') | |
| P('hi', hx_get=foo, hx_trigger='load', hx_target=c) | |
| ``` | |
| <div id="_mmZ8zN0IQRWcwaaJuPD17g"> | |
| <p hx-get="/foo" hx-trigger="load" hx-target="#_dazDkLiNRi_5IRjKxnDApQ" id="_21sjPwFeSPKp3vncj4YJrQ"> | |
| hi | |
| </p> | |
| <script id="_iy4Ov4wQRsuuB6ekh8semw">if (window.htmx) htmx.process(document.body)</script> | |
| </div> | |
| ``` python | |
| server.stop() | |
| ``` | |
| ### Running apps in an IFrame | |
| Using an IFrame can be a good idea to get complete isolation of the | |
| styles and scripts in an app. The | |
| [`HTMX`](https://www.fastht.ml/docs/api/jupyter.html#htmx) function | |
| creates an auto-sizing IFrame for a web app. | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L114" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### HTMX | |
| > HTMX (path='', app=None, host='localhost', port=8000, height='auto', | |
| > link=False, iframe=True) | |
| *An iframe which displays the HTMX application in a notebook.* | |
| ``` python | |
| @rt | |
| def index(): | |
| return Div( | |
| P(A('Click me', hx_get=update, hx_target='#result')), | |
| P(A('No me!', hx_get=update, hx_target='#result')), | |
| Div(id='result')) | |
| @rt | |
| def update(): return Div(P('Hi!'),P('There!')) | |
| ``` | |
| ``` python | |
| server.start() | |
| ``` | |
| ``` python | |
| # Run the notebook locally to see the HTMX iframe in action | |
| HTMX() | |
| ``` | |
| <iframe src="http://localhost:8000" style="width: 100%; height: auto; border: none;" onload="{ | |
| let frame = this; | |
| window.addEventListener('message', function(e) { | |
| if (e.source !== frame.contentWindow) return; // Only proceed if the message is from this iframe | |
| if (e.data.height) frame.style.height = (e.data.height+1) + 'px'; | |
| }, false); | |
| }" allow="accelerometer; autoplay; camera; clipboard-read; clipboard-write; display-capture; encrypted-media; fullscreen; gamepad; geolocation; gyroscope; hid; identity-credentials-get; idle-detection; magnetometer; microphone; midi; payment; picture-in-picture; publickey-credentials-get; screen-wake-lock; serial; usb; web-share; xr-spatial-tracking"></iframe> | |
| ``` python | |
| server.stop() | |
| ``` | |
| ------------------------------------------------------------------------ | |
| <a | |
| href="https://github.com/AnswerDotAI/fasthtml/blob/main/fasthtml/jupyter.py#L135" | |
| target="_blank" style="float:right; font-size:smaller">source</a> | |
| ### ws_client | |
| > ws_client (app, nm='', host='localhost', port=8000, ws_connect='/ws', | |
| > frame=True, link=True, **kwargs) | |