From 62a162b0bcdfe4f4779dfcb0d2ea10790c751d7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:26:05 +0300 Subject: [PATCH 1/7] Point the By Example curl example at port 5001 --- nbs/tutorials/by_example.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nbs/tutorials/by_example.ipynb b/nbs/tutorials/by_example.ipynb index d1ddf92c..2671ed77 100644 --- a/nbs/tutorials/by_example.ipynb +++ b/nbs/tutorials/by_example.ipynb @@ -345,7 +345,7 @@ ":::{.callout-tip}\n", "## Test the POST request\n", "\n", - "You can test the POST request with `curl -X POST http://127.0.0.1:8000 -d \"some data\"`. This sends some data to the server, you should see the response \"got a post or put request\" printed in the terminal.\n", + "You can test the POST request with `curl -X POST http://127.0.0.1:5001 -d \"some data\"`. This sends some data to the server, you should see the response \"got a post or put request\" printed in the terminal.\n", ":::\n", "\n", "There are a few other ways you can specify the route+method - FastHTML has `.get`, `.post`, etc. as shorthand for `route(..., methods=['get'])`, etc." From cae365d92d2bf9c7d1854177ee603c3c72888a4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:29:37 +0300 Subject: [PATCH 2/7] Import Pico, uuid, and sleep at their first use --- nbs/tutorials/by_example.ipynb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/nbs/tutorials/by_example.ipynb b/nbs/tutorials/by_example.ipynb index 2671ed77..f707666b 100644 --- a/nbs/tutorials/by_example.ipynb +++ b/nbs/tutorials/by_example.ipynb @@ -586,6 +586,7 @@ "outputs": [], "source": [ "from fasthtml.common import *\n", + "from fasthtml.pico import *\n", "css = Style(':root {--pico-font-size:90%;--pico-font-family: Pacifico, cursive;}') # <1>\n", "app = FastHTML(hdrs=(picolink, css)) # <2>\n", "\n", @@ -1014,6 +1015,8 @@ "At the moment everyone sees all images! How do we keep some sort of unique identifier tied to a user? Before going all the way to setting up users, login pages etc., let's look at a way to at least limit generations to the user's *session*. You could do this manually with cookies. For convenience and security, fasthtml (via Starlette) has a special mechanism for storing small amounts of data in the user's browser via the `session` argument to your route. This acts like a dictionary and you can set and get values from it. For example, here we look for a `session_id` key, and if it doesn't exist we generate a new one:\n", "\n", "```python\n", + "import uuid\n", + "\n", "@app.get(\"/\")\n", "def get(session):\n", " if 'session_id' not in session: session['session_id'] = str(uuid.uuid4())\n", @@ -1610,6 +1613,8 @@ "And this will setup a connection on the route `/ws` along with a form that will send a message to the websocket whenever the form is submitted. Let's go ahead and handle this route:\n", "\n", "```python\n", + "from asyncio import sleep\n", + "\n", "@app.ws('/ws')\n", "async def ws(msg:str, send):\n", " await send(Div('Hello ' + msg, id=\"notifications\"))\n", From 80baad1060a214ca6989dcdd6fd3a609c1cdde04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:40:50 +0300 Subject: [PATCH 3/7] List the examples that exist and the fastlite install --- examples/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/README.md b/examples/README.md index 4ddedc00..567c5888 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,4 +1,4 @@ # Examples -This directory contains some examples of the library in action, including a sequence of to-do list apps of increasing complexity (see `todos1.py` through `todos5.py`, along with `adv_app.py`). For more examples of different applications and components, see the separate [examples repository](https://github.com/AnswerDotAI/fasthtml-example). +This directory contains some examples of the library in action, including a sequence of to-do list apps of increasing complexity (see `todos1.py` through `todos4.py`, along with `adv_app.py`). Examples that open a database also need `fastlite` (`pip install fastlite`). It is not installed with `python-fasthtml` alone. For more examples of different applications and components, see the separate [examples repository](https://github.com/AnswerDotAI/fasthtml-example). From 00811483182694e689b7ef8c8a3d195b072d41a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:40:50 +0300 Subject: [PATCH 4/7] Import Pico in the examples and the demo --- demo/main.py | 1 + examples/todos1.py | 1 + examples/todos2.py | 1 + examples/todos3.py | 1 + examples/todos4.py | 1 + examples/user_app.py | 1 + 6 files changed, 6 insertions(+) diff --git a/demo/main.py b/demo/main.py index 666c1d90..22f1936b 100644 --- a/demo/main.py +++ b/demo/main.py @@ -1,4 +1,5 @@ from fasthtml.common import * +from fasthtml.pico import * def render(item:'Todo'): id = f'todo-{item.id}' diff --git a/examples/todos1.py b/examples/todos1.py index 0f2612ca..8b9ec912 100644 --- a/examples/todos1.py +++ b/examples/todos1.py @@ -1,4 +1,5 @@ from fasthtml.common import * +from fasthtml.pico import * app,rt,todos,Todo = fast_app('data/todos.db', id=int, task=str, done=bool, pk='id') diff --git a/examples/todos2.py b/examples/todos2.py index 27e207b6..75b43230 100644 --- a/examples/todos2.py +++ b/examples/todos2.py @@ -1,4 +1,5 @@ from fasthtml.common import * +from fasthtml.pico import * id_curr = 'current-todo' id_list = 'todo-list' diff --git a/examples/todos3.py b/examples/todos3.py index e0031173..aa09b119 100644 --- a/examples/todos3.py +++ b/examples/todos3.py @@ -1,5 +1,6 @@ # Run with: python basic_app.py from fasthtml.common import * +from fasthtml.pico import * def render(todo): show = AX(todo.task, f'/todos/{todo.id}', 'current-todo') diff --git a/examples/todos4.py b/examples/todos4.py index 09a46e9e..f9cc84ba 100644 --- a/examples/todos4.py +++ b/examples/todos4.py @@ -1,4 +1,5 @@ from fasthtml.common import * +from fasthtml.pico import * from fastlite import * db = database('data/todos.db') diff --git a/examples/user_app.py b/examples/user_app.py index 10087d7b..534923f3 100644 --- a/examples/user_app.py +++ b/examples/user_app.py @@ -1,6 +1,7 @@ # Run with: python user_app.py # At signin, enter a user/pw combination and if it doesn't exist, it will be created. from fasthtml.common import * +from fasthtml.pico import * from fastlite import * db = database('data/utodos.db') From 92e49d096f25233e9579202984fcfa7f971c6a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:40:50 +0300 Subject: [PATCH 5/7] Use Pico for the layout tags in pep8_app --- examples/pep8_app.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/examples/pep8_app.py b/examples/pep8_app.py index 68d4ac96..f73d0fae 100644 --- a/examples/pep8_app.py +++ b/examples/pep8_app.py @@ -5,6 +5,7 @@ # This fasthtml app includes functionality from fastcore, starlette, fastlite, and fasthtml itself. # Run with: `python adv_app.py` from fasthtml import common as fh +from fasthtml import pico from hmac import compare_digest from dataclasses import dataclass from fastcore.utils import patch @@ -108,16 +109,16 @@ def __ft__(self: Todo): @app.get("/") def get(auth): title = f"{auth}'s Todo list" - top = fh.Grid(fh.H1(title), fh.Div(fh.A('logout', href='/logout'), style='text-align: right')) + top = pico.Grid(fh.H1(title), fh.Div(fh.A('logout', href='/logout'), style='text-align: right')) new_inp = fh.Input(id="new-title", name="title", placeholder="New Todo") - grp = fh.Group(new_inp, fh.Button("Add")) + grp = pico.Group(new_inp, fh.Button("Add")) add = fh.Form(grp, hx_post="/", target_id='todo-list', hx_swap="afterbegin") # In the MiniDataAPI spec, treating a table as a callable (i.e with `todos(...)` here) queries the table. frm = fh.Form(*todos(order_by='priority'), id='todo-list', cls='sortable', hx_post="/reorder", hx_trigger="end") # We create an empty 'current-todo' Div at the bottom of our page, as a target for the details and editing views. - card = fh.Card(fh.Ul(frm), header=add, footer=fh.Div(id='current-todo')) + card = pico.Card(fh.Ul(frm), header=add, footer=fh.Div(id='current-todo')) # PicoCSS uses `
` page content; `Container` is a tiny function that generates that. - return fh.Title(title), fh.Container(top, card) + return fh.Title(title), pico.Container(top, card) # This is the handler for the reordering of todos. @@ -146,7 +147,7 @@ def delete(id: int): def edit(id: int): # The `hx_put` attribute tells HTMX to send a PUT request when the form is submitted. res = fh.Form(hx_put="/", target_id=f'todo-{id}', id="edit")( - fh.Group(fh.Input(id="title"), fh.Button("Save")), + pico.Group(fh.Input(id="title"), fh.Button("Save")), fh.Hidden(id="id"), fh.CheckboxX(id="done", label='Done'), fh.Textarea(id="details", name="details", rows=10), From 89ce558071bc568bf5779d9a4d3889336e755b43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:40:50 +0300 Subject: [PATCH 6/7] Import database and NotFoundError from fastlite in pep8_app --- examples/pep8_app.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/pep8_app.py b/examples/pep8_app.py index f73d0fae..04f12eea 100644 --- a/examples/pep8_app.py +++ b/examples/pep8_app.py @@ -6,6 +6,7 @@ # Run with: `python adv_app.py` from fasthtml import common as fh from fasthtml import pico +from fastlite import NotFoundError, database from hmac import compare_digest from dataclasses import dataclass from fastcore.utils import patch @@ -25,7 +26,7 @@ class Todo: priority: int -db = fh.database('data/todos_p8.db') +db = database('data/todos_p8.db') users = db.create(User, pk='name') todos = db.create(Todo) @@ -72,7 +73,7 @@ def login_post(login: Login, sess): # Indexing into a MiniDataAPI table queries by primary key, which is `name` here. try: u = users[login.name] - except fh.NotFoundError: + except NotFoundError: u = users.insert(login) if not compare_digest(u.pwd.encode("utf-8"), login.pwd.encode("utf-8")): return login_redir # Because the session is signed, we can securely add information to it. From c3e9f510b0199f138a62c3a37203f0813780d556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Mon, 12 Oct 2026 16:40:50 +0300 Subject: [PATCH 7/7] List fastlite in the demo requirements --- demo/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/demo/requirements.txt b/demo/requirements.txt index c5f7ff3a..99c1ac42 100644 --- a/demo/requirements.txt +++ b/demo/requirements.txt @@ -1 +1,2 @@ -python-fasthtml \ No newline at end of file +python-fasthtml +fastlite \ No newline at end of file