From b207fe163109946079fac26af0f01a2ad3c313fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Fri, 9 Oct 2026 18:28:52 +0300 Subject: [PATCH 01/10] Remove the outdated `pyproject.toml` answer from the FAQ --- nbs/explains/faq.ipynb | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/nbs/explains/faq.ipynb b/nbs/explains/faq.ipynb index 313cba3f..c7cb85bf 100644 --- a/nbs/explains/faq.ipynb +++ b/nbs/explains/faq.ipynb @@ -144,24 +144,6 @@ "[nbdev](https://nbdev.fast.ai/) is a Jupyter-powered tool for writing software. Traditional programming environments throw away the result of your exploration in REPLs or notebooks. `nbdev` makes exploration an integral part of your workflow, all while promoting software engineering best practices." ] }, - { - "cell_type": "markdown", - "id": "9ad687c4", - "metadata": {}, - "source": [ - "## Why not pyproject.toml for packaging?" - ] - }, - { - "cell_type": "markdown", - "id": "d5f9d9d3", - "metadata": {}, - "source": [ - "FastHTML uses a `setup.py` module instead of a `pyproject.toml` file to configure itself for installation. The reason for this is `pyproject.toml` is not compatible with [nbdev](https://nbdev.fast.ai/), which is what is used to write and build FastHTML.\n", - "\n", - "The nbdev project spent around a year trying to move to pyproject.toml but there was insufficient functionality in the toml-based approach to complete the transition." - ] - }, { "cell_type": "code", "execution_count": null, From 236f5c08c5ebdf2cc52aa1dcd966dd4a1bd791dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Fri, 9 Oct 2026 18:28:53 +0300 Subject: [PATCH 02/10] Replace "three years" with "many years" in the FAQ --- nbs/explains/faq.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nbs/explains/faq.ipynb b/nbs/explains/faq.ipynb index c7cb85bf..4c280552 100644 --- a/nbs/explains/faq.ipynb +++ b/nbs/explains/faq.ipynb @@ -139,7 +139,7 @@ "source": [ "Some people are under the impression that writing software in notebooks is bad.\n", "\n", - "[Watch this video](https://www.youtube.com/watch?v=9Q6sLbz37gk&ab_channel=JeremyHoward). We've used Jupyter notebooks exported via `nbdev` to write a wide range of “very serious” software projects over the last three years. This includes deep learning libraries, API clients, Python language extensions, terminal user interfaces, web frameworks, and more!\n", + "[Watch this video](https://www.youtube.com/watch?v=9Q6sLbz37gk&ab_channel=JeremyHoward). We've used Jupyter notebooks exported via `nbdev` to write a wide range of “very serious” software projects over many years. This includes deep learning libraries, API clients, Python language extensions, terminal user interfaces, web frameworks, and more!\n", "\n", "[nbdev](https://nbdev.fast.ai/) is a Jupyter-powered tool for writing software. Traditional programming environments throw away the result of your exploration in REPLs or notebooks. `nbdev` makes exploration an integral part of your workflow, all while promoting software engineering best practices." ] From 3bf97f766fe9403de74f84a126e5cad890313d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Fri, 9 Oct 2026 18:28:53 +0300 Subject: [PATCH 03/10] Show the Pylance settings as keys to merge into `settings.json` --- nbs/explains/faq.ipynb | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/nbs/explains/faq.ipynb b/nbs/explains/faq.ipynb index 4c280552..50473073 100644 --- a/nbs/explains/faq.ipynb +++ b/nbs/explains/faq.ipynb @@ -22,35 +22,32 @@ "id": "5c34ab11", "metadata": {}, "source": [ - "Many editors, including Visual Studio Code, use PyLance to provide error checking for Python. However, PyLance's error checking is just a guess -- it can't actually know whether your code is correct or not. PyLance particularly struggles with FastHTML's syntax, which leads to it often reporting false error messages in FastHTML projects.\n", + "Many editors, including Visual Studio Code, use Pylance to provide error checking for Python. However, Pylance's error checking is just a guess -- it can't actually know whether your code is correct or not. Pylance particularly struggles with FastHTML's syntax, which leads to it often reporting false error messages in FastHTML projects.\n", "\n", - "To avoid these misleading error messages, it's best to disable some PyLance error checking in your FastHTML projects. Here's how to do it in Visual Studio Code (the same approach should also work in other editors based on vscode, such as Cursor and GitHub Codespaces):\n", + "To avoid these misleading error messages, it's best to disable some Pylance error checking in your FastHTML projects. Here's how to do it in Visual Studio Code (the same approach should also work in other editors based on VS Code, such as Cursor and GitHub Codespaces):\n", "\n", "1. Open your FastHTML project\n", "2. Press `Ctrl+Shift+P` (or `Cmd+Shift+P` on Mac) to open the Command Palette\n", "3. Type \"Preferences: Open Workspace Settings (JSON)\" and select it\n", - "4. In the JSON file that opens, add the following lines:\n", - "```json\n", - "{\n", - " \"python.analysis.diagnosticSeverityOverrides\": {\n", + "4. In the JSON file that opens, add the following lines to the existing dictionary:\n", + "\n", + " ```json\n", + " \"python.analysis.diagnosticSeverityOverrides\": {\n", " \"reportGeneralTypeIssues\": \"none\",\n", " \"reportOptionalMemberAccess\": \"none\",\n", " \"reportWildcardImportFromLibrary\": \"none\",\n", " \"reportRedeclaration\": \"none\",\n", " \"reportAttributeAccessIssue\": \"none\",\n", " \"reportInvalidTypeForm\": \"none\",\n", - " \"reportAssignmentType\": \"none\",\n", - " }\n", - "}\n", - "```\n", + " \"reportAssignmentType\": \"none\"\n", + " }\n", + " ```\n", "5. Save the file\n", "\n", - "Even with PyLance diagnostics turned off, your FastHTML code will still run correctly. If you're still seeing some false errors from PyLance, you can disable it entirely by adding this to your settings:\n", + "Even with Pylance diagnostics turned off, your FastHTML code will still run correctly. If you're still seeing some false errors from Pylance, you can disable it entirely by adding this to your settings:\n", "\n", "```json\n", - "{\n", - " \"python.analysis.ignore\": [ \"*\" ]\n", - "}\n", + "\"python.analysis.ignore\": [\"*\"]\n", "```" ] }, From 57185ec251eb3458084041a2f4c548e9ae69b17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sat, 10 Oct 2026 12:20:27 +0300 Subject: [PATCH 04/10] Correct the `frustration` typo in the `FT` explainer --- nbs/explains/explaining_xt_components.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nbs/explains/explaining_xt_components.ipynb b/nbs/explains/explaining_xt_components.ipynb index a3ac321d..5b617c82 100644 --- a/nbs/explains/explaining_xt_components.ipynb +++ b/nbs/explains/explaining_xt_components.ipynb @@ -315,7 +315,7 @@ "source": [ "If you use type hints, we strongly suggest that FT components be treated as the `Any` type.\n", "\n", - "The reason is that FastHTML leverages python's dynamic features to a great degree. Especially when it comes to `FT` components, which can evaluate out to be `FT|str|None|tuple` as well as anything that supports the `__ft__`, `__html__`, and `__str__` method. That's enough of the Python stack that assigning anything but `Any` to be the FT type will prove an exercise in frustation." + "The reason is that FastHTML leverages python's dynamic features to a great degree. Especially when it comes to `FT` components, which can evaluate out to be `FT|str|None|tuple` as well as anything that supports the `__ft__`, `__html__`, and `__str__` method. That's enough of the Python stack that assigning anything but `Any` to be the FT type will prove an exercise in frustration." ] } ], From 03a0a134a335cac92a419d452a6d94c00adfca75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sat, 10 Oct 2026 12:20:28 +0300 Subject: [PATCH 05/10] Import `fastlite` in the background-task example --- nbs/explains/background_tasks.ipynb | 1 + 1 file changed, 1 insertion(+) diff --git a/nbs/explains/background_tasks.ipynb b/nbs/explains/background_tasks.ipynb index 5f445246..e8da3d28 100644 --- a/nbs/explains/background_tasks.ipynb +++ b/nbs/explains/background_tasks.ipynb @@ -159,6 +159,7 @@ "```python\n", "# main.py\n", "from fasthtml.common import *\n", + "from fastlite import *\n", "from starlette.background import BackgroundTask\n", "import time\n", "import httpx\n", From 2b23d8ff6240f9b721baf4c10a49c12e485be790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sat, 10 Oct 2026 18:28:39 +0300 Subject: [PATCH 06/10] Name `httpx2` where a reader would import or be told the package --- nbs/api/06_jupyter.ipynb | 2 +- nbs/explains/background_tasks.ipynb | 4 ++-- nbs/explains/routes.ipynb | 2 +- nbs/ref/handlers.ipynb | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nbs/api/06_jupyter.ipynb b/nbs/api/06_jupyter.ipynb index f9a542e9..1b056565 100644 --- a/nbs/api/06_jupyter.ipynb +++ b/nbs/api/06_jupyter.ipynb @@ -48,7 +48,7 @@ "metadata": {}, "outputs": [], "source": [ - "from httpx import get, AsyncClient" + "from httpx2 import get, AsyncClient" ] }, { diff --git a/nbs/explains/background_tasks.ipynb b/nbs/explains/background_tasks.ipynb index e8da3d28..91cb598c 100644 --- a/nbs/explains/background_tasks.ipynb +++ b/nbs/explains/background_tasks.ipynb @@ -162,7 +162,7 @@ "from fastlite import *\n", "from starlette.background import BackgroundTask\n", "import time\n", - "import httpx\n", + "import httpx2\n", "\n", "app, rt = fast_app()\n", "\n", @@ -173,7 +173,7 @@ "tstamps = db.create(TStamp, pk='request_time')\n", "\n", "def task_submit(request_time: int): # <2>\n", - " client = httpx.Client()\n", + " client = httpx2.Client()\n", " response = client.post(f'http://127.0.0.1:8123/slow?ts={request_time}') # <3>\n", " tstamps.insert(**response.json()) # <4>\n", "\n", diff --git a/nbs/explains/routes.ipynb b/nbs/explains/routes.ipynb index 257a7cd9..581fcd1d 100644 --- a/nbs/explains/routes.ipynb +++ b/nbs/explains/routes.ipynb @@ -97,7 +97,7 @@ "id": "fc76abcd", "metadata": {}, "source": [ - "TestClient uses `httpx` behind the scenes, so it returns a `httpx.Response`, which has a `text` attribute with our response body:" + "TestClient uses `httpx2` behind the scenes, so it returns an `httpx2.Response`, which has a `text` attribute with our response body:" ] }, { diff --git a/nbs/ref/handlers.ipynb b/nbs/ref/handlers.ipynb index e1436259..bf8cd39e 100644 --- a/nbs/ref/handlers.ipynb +++ b/nbs/ref/handlers.ipynb @@ -131,7 +131,7 @@ "id": "42c18142", "metadata": {}, "source": [ - "The `get` method on a `Client` instance simulates GET requests to the app. It returns a response object that has a `.text` attribute, which you can use to access the body of the response. It calls `httpx.get` internally -- all httpx HTTP verbs are supported." + "The `get` method on a `Client` instance simulates GET requests to the app. It returns a response object that has a `.text` attribute, which you can use to access the body of the response. It calls `httpx2.get` internally -- all httpx2 HTTP verbs are supported." ] }, { From cb5c03385d9ce06044b128a3d4e31993f76dbc23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sat, 10 Oct 2026 18:30:19 +0300 Subject: [PATCH 07/10] Fix the `cookies` and `FastHTML` typos --- fasthtml/core.py | 2 +- fasthtml/core.pyi | 2 +- nbs/api/00_core.ipynb | 2 +- nbs/apilist.txt | 2 +- nbs/llms-ctx-full.txt | 4 ++-- nbs/ref/handlers.ipynb | 2 +- nbs/tutorials/e2e.ipynb | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/fasthtml/core.py b/fasthtml/core.py index e1539238..16202e28 100644 --- a/fasthtml/core.py +++ b/fasthtml/core.py @@ -1175,7 +1175,7 @@ def devtools(): return dict(workspace=dict(root=str(path), uuid=uuid)) # %% ../nbs/api/00_core.ipynb #e27908c0 @patch def get_client(self:FastHTML, asink=False, **kw): - "Get an httpx client with session cookes set from `**kw`" + "Get an httpx client with session cookies set from `**kw`" import httpx2 signer = itsdangerous.TimestampSigner(self.secret_key) data = b64encode(dumps(kw).encode()) diff --git a/fasthtml/core.pyi b/fasthtml/core.pyi index 3ec037c6..6151e439 100644 --- a/fasthtml/core.pyi +++ b/fasthtml/core.pyi @@ -367,7 +367,7 @@ class FastHTML(Starlette): ... def get_client(self, asink=False, **kw): - """Get an httpx client with session cookes set from `**kw`""" + """Get an httpx client with session cookies set from `**kw`""" ... def decode_session(self, cookie): diff --git a/nbs/api/00_core.ipynb b/nbs/api/00_core.ipynb index 1fa7a1c4..9631bbba 100644 --- a/nbs/api/00_core.ipynb +++ b/nbs/api/00_core.ipynb @@ -5145,7 +5145,7 @@ "#| export\n", "@patch\n", "def get_client(self:FastHTML, asink=False, **kw):\n", - " \"Get an httpx client with session cookes set from `**kw`\"\n", + " \"Get an httpx client with session cookies set from `**kw`\"\n", " import httpx2\n", " signer = itsdangerous.TimestampSigner(self.secret_key)\n", " data = b64encode(dumps(kw).encode())\n", diff --git a/nbs/apilist.txt b/nbs/apilist.txt index 91de862c..c00533ed 100644 --- a/nbs/apilist.txt +++ b/nbs/apilist.txt @@ -229,7 +229,7 @@ - `@patch def setup_ws(app, f)` - `@patch def devtools_json(self, path, uuid)` - `@patch def get_client(self, asink, **kw)` - Get an httpx client with session cookes set from `**kw` + Get an httpx client with session cookies set from `**kw` - `@patch def decode_session(self, cookie)` Decode a signed session cookie diff --git a/nbs/llms-ctx-full.txt b/nbs/llms-ctx-full.txt index fa8c441c..2bc9aa65 100644 --- a/nbs/llms-ctx-full.txt +++ b/nbs/llms-ctx-full.txt @@ -5123,7 +5123,7 @@ tutorial we’ll be using Railway. To get started, make sure you create an CLI](https://docs.railway.app/guides/cli). Once installed, make sure to run `railway login` to log in to your account. -To make deploying your website as easy as possible, FastHTMl comes with +To make deploying your website as easy as possible, FastHTML comes with a built in CLI tool that will handle most of the deployment process for you. To deploy your website, run the following command in your terminal in the root directory of your project: @@ -9691,7 +9691,7 @@ tags, which are both placed in the head. [`APIRouter`](https://www.fastht.ml/docs/api/core.html#apirouter) is useful when you want to split your application routes across multiple -`.py` files that are part of a single FastHTMl application. It accepts +`.py` files that are part of a single FastHTML application. It accepts an optional `prefix` argument that will be applied to all routes within that instance of [`APIRouter`](https://www.fastht.ml/docs/api/core.html#apirouter). diff --git a/nbs/ref/handlers.ipynb b/nbs/ref/handlers.ipynb index bf8cd39e..533dfa67 100644 --- a/nbs/ref/handlers.ipynb +++ b/nbs/ref/handlers.ipynb @@ -1310,7 +1310,7 @@ "id": "f8138c07", "metadata": {}, "source": [ - "`APIRouter` is useful when you want to split your application routes across multiple `.py` files that are part of a single FastHTMl application. It accepts an optional `prefix` argument that will be applied to all routes within that instance of `APIRouter`.\n", + "`APIRouter` is useful when you want to split your application routes across multiple `.py` files that are part of a single FastHTML application. It accepts an optional `prefix` argument that will be applied to all routes within that instance of `APIRouter`.\n", "\n", "Below we define several hypothetical product related routes in a `products.py` and then demonstrate how they can seamlessly be incorporated into a FastHTML app instance." ] diff --git a/nbs/tutorials/e2e.ipynb b/nbs/tutorials/e2e.ipynb index 234c0a96..e7653c54 100644 --- a/nbs/tutorials/e2e.ipynb +++ b/nbs/tutorials/e2e.ipynb @@ -476,7 +476,7 @@ "source": [ "You can deploy your website to a number of hosting providers, for this tutorial we'll be using Railway. To get started, make sure you create an [account](https://railway.app/) and install the [Railway CLI](https://docs.railway.app/guides/cli). Once installed, make sure to run `railway login` to log in to your account.\n", "\n", - "To make deploying your website as easy as possible, FastHTMl comes with a built in CLI tool that will handle most of the deployment process for you. To deploy your website, run the following command in your terminal in the root directory of your project:\n", + "To make deploying your website as easy as possible, FastHTML comes with a built in CLI tool that will handle most of the deployment process for you. To deploy your website, run the following command in your terminal in the root directory of your project:\n", "\n", "```sh\n", "fh_railway_deploy quickdraw\n", From b09003e31c517e185cadf868b8c855635270949f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sat, 10 Oct 2026 12:47:37 +0300 Subject: [PATCH 08/10] Give the Jupyter tutorial link an `http` scheme --- nbs/tutorials/jupyter_and_fasthtml.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nbs/tutorials/jupyter_and_fasthtml.ipynb b/nbs/tutorials/jupyter_and_fasthtml.ipynb index 12f5fadd..e35a43c0 100644 --- a/nbs/tutorials/jupyter_and_fasthtml.ipynb +++ b/nbs/tutorials/jupyter_and_fasthtml.ipynb @@ -168,7 +168,7 @@ "id": "4cb6bb90", "metadata": {}, "source": [ - "You can view your app outside of Jupyter by going to `localhost:PORT`, where `PORT` is usually the default 8000, so in most cases just click [this link](localhost:8000/)." + "You can view your app outside of Jupyter by going to `localhost:PORT`, where `PORT` is usually the default 8000, so in most cases just click [this link](http://localhost:8000/)." ] }, { From 4220479810a398992feca7d46d4c155ef32f829c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sat, 10 Oct 2026 17:44:03 +0300 Subject: [PATCH 09/10] Drop the repeated opening sentence in the Jupyter tutorial --- nbs/tutorials/jupyter_and_fasthtml.ipynb | 2 -- 1 file changed, 2 deletions(-) diff --git a/nbs/tutorials/jupyter_and_fasthtml.ipynb b/nbs/tutorials/jupyter_and_fasthtml.ipynb index e35a43c0..b7338083 100644 --- a/nbs/tutorials/jupyter_and_fasthtml.ipynb +++ b/nbs/tutorials/jupyter_and_fasthtml.ipynb @@ -17,8 +17,6 @@ "id": "4b1ee344", "metadata": {}, "source": [ - "Writing FastHTML applications in Jupyter notebooks requires a slightly different process than normal Python applications. \n", - "\n", ":::{.callout-tip title='Download this notebook and try it yourself'}\n", "The source code for this page is a [Jupyter notebook](https://github.com/AnswerDotAI/fasthtml/blob/main/nbs/tutorials/jupyter_and_fasthtml.ipynb). That makes it easy to directly experiment with it. However, as this is working code that means we have to comment out a few things in order for the documentation to build.\n", ":::\n", From 23a27551a8f2828c72d83fb31a24ec1a22657bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=2E=20Tolga=20Cang=C3=B6z?= Date: Sun, 11 Oct 2026 14:47:51 +0300 Subject: [PATCH 10/10] Import `fastlite` in the e2e tutorial and note the deploy requirements --- nbs/tutorials/e2e.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nbs/tutorials/e2e.ipynb b/nbs/tutorials/e2e.ipynb index e7653c54..29eccb8e 100644 --- a/nbs/tutorials/e2e.ipynb +++ b/nbs/tutorials/e2e.ipynb @@ -142,7 +142,7 @@ "1. Room Creation and Storage\n", "\n", "```{.python filename=\"main.py\"}\n", - "db = database('data/drawapp.db')\n", + "from fastlite import *\ndb = database('data/drawapp.db')\n", "rooms = db.t.rooms\n", "if rooms not in db.t:\n", " rooms.create(id=int, name=str, created_at=str, pk='id')\n", @@ -483,7 +483,7 @@ "```\n", "\n", "::: {.callout-note}\n", - "Your app must be located in a `main.py` file for this to work.\n", + "Your app must be located in a `main.py` file for this to work. If `requirements.txt` is missing, this command creates one that lists only `python-fasthtml`. This app also needs `fastlite`, so add that line before you deploy.\n", ":::" ] },