]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🛠️ Update `docs.py generate-readme` command to remove permalinks from headers (#14055)
authorMotov Yurii <109919500+YuriiMotov@users.noreply.github.com>
Sat, 20 Sep 2025 11:43:51 +0000 (13:43 +0200)
committerGitHub <noreply@github.com>
Sat, 20 Sep 2025 11:43:51 +0000 (13:43 +0200)
README.md
scripts/docs.py

index 6f13f9eae6ee549ee794d3a2e6f1f0278780b6e0..a8a0e37b52dc78cf696a40aacf460d357747c012 100644 (file)
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ The key features are:
 
 <small>* estimation based on tests on an internal development team, building production applications.</small>
 
-## Sponsors { #sponsors }
+## Sponsors
 
 <!-- sponsors -->
 
@@ -67,7 +67,7 @@ The key features are:
 
 <a href="https://fastapi.tiangolo.com/fastapi-people/#sponsors" class="external-link" target="_blank">Other sponsors</a>
 
-## Opinions { #opinions }
+## Opinions
 
 "_[...] I'm using **FastAPI** a ton these days. [...] I'm actually planning to use it for all of my team's **ML services at Microsoft**. Some of them are getting integrated into the core **Windows** product and some **Office** products._"
 
@@ -113,7 +113,7 @@ The key features are:
 
 ---
 
-## **Typer**, the FastAPI of CLIs { #typer-the-fastapi-of-clis }
+## **Typer**, the FastAPI of CLIs
 
 <a href="https://typer.tiangolo.com" target="_blank"><img src="https://typer.tiangolo.com/img/logo-margin/logo-margin-vector.svg" style="width: 20%;"></a>
 
@@ -121,14 +121,14 @@ If you are building a <abbr title="Command Line Interface">CLI</abbr> app to be
 
 **Typer** is FastAPI's little sibling. And it's intended to be the **FastAPI of CLIs**. ⌨️ 🚀
 
-## Requirements { #requirements }
+## Requirements
 
 FastAPI stands on the shoulders of giants:
 
 * <a href="https://www.starlette.io/" class="external-link" target="_blank">Starlette</a> for the web parts.
 * <a href="https://docs.pydantic.dev/" class="external-link" target="_blank">Pydantic</a> for the data parts.
 
-## Installation { #installation }
+## Installation
 
 Create and activate a <a href="https://fastapi.tiangolo.com/virtual-environments/" class="external-link" target="_blank">virtual environment</a> and then install FastAPI:
 
@@ -144,9 +144,9 @@ $ pip install "fastapi[standard]"
 
 **Note**: Make sure you put `"fastapi[standard]"` in quotes to ensure it works in all terminals.
 
-## Example { #example }
+## Example
 
-### Create it { #create-it }
+### Create it
 
 Create a file `main.py` with:
 
@@ -197,7 +197,7 @@ If you don't know, check the _"In a hurry?"_ section about <a href="https://fast
 
 </details>
 
-### Run it { #run-it }
+### Run it
 
 Run the server with:
 
@@ -239,7 +239,7 @@ You can read more about it in the <a href="https://fastapi.tiangolo.com/fastapi-
 
 </details>
 
-### Check it { #check-it }
+### Check it
 
 Open your browser at <a href="http://127.0.0.1:8000/items/5?q=somequery" class="external-link" target="_blank">http://127.0.0.1:8000/items/5?q=somequery</a>.
 
@@ -256,7 +256,7 @@ You already created an API that:
 * The _path_ `/items/{item_id}` has a _path parameter_ `item_id` that should be an `int`.
 * The _path_ `/items/{item_id}` has an optional `str` _query parameter_ `q`.
 
-### Interactive API docs { #interactive-api-docs }
+### Interactive API docs
 
 Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
 
@@ -264,7 +264,7 @@ You will see the automatic interactive API documentation (provided by <a href="h
 
 ![Swagger UI](https://fastapi.tiangolo.com/img/index/index-01-swagger-ui-simple.png)
 
-### Alternative API docs { #alternative-api-docs }
+### Alternative API docs
 
 And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
 
@@ -272,7 +272,7 @@ You will see the alternative automatic documentation (provided by <a href="https
 
 ![ReDoc](https://fastapi.tiangolo.com/img/index/index-02-redoc-simple.png)
 
-## Example upgrade { #example-upgrade }
+## Example upgrade
 
 Now modify the file `main.py` to receive a body from a `PUT` request.
 
@@ -310,7 +310,7 @@ def update_item(item_id: int, item: Item):
 
 The `fastapi dev` server should reload automatically.
 
-### Interactive API docs upgrade { #interactive-api-docs-upgrade }
+### Interactive API docs upgrade
 
 Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_blank">http://127.0.0.1:8000/docs</a>.
 
@@ -326,7 +326,7 @@ Now go to <a href="http://127.0.0.1:8000/docs" class="external-link" target="_bl
 
 ![Swagger UI interaction](https://fastapi.tiangolo.com/img/index/index-05-swagger-04.png)
 
-### Alternative API docs upgrade { #alternative-api-docs-upgrade }
+### Alternative API docs upgrade
 
 And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" target="_blank">http://127.0.0.1:8000/redoc</a>.
 
@@ -334,7 +334,7 @@ And now, go to <a href="http://127.0.0.1:8000/redoc" class="external-link" targe
 
 ![ReDoc](https://fastapi.tiangolo.com/img/index/index-06-redoc-02.png)
 
-### Recap { #recap }
+### Recap
 
 In summary, you declare **once** the types of parameters, body, etc. as function parameters.
 
@@ -446,17 +446,17 @@ For a more complete example including more features, see the <a href="https://fa
     * **Cookie Sessions**
     * ...and more.
 
-## Performance { #performance }
+## Performance
 
 Independent TechEmpower benchmarks show **FastAPI** applications running under Uvicorn as <a href="https://www.techempower.com/benchmarks/#section=test&runid=7464e520-0dc2-473d-bd34-dbdfd7e85911&hw=ph&test=query&l=zijzen-7" class="external-link" target="_blank">one of the fastest Python frameworks available</a>, only below Starlette and Uvicorn themselves (used internally by FastAPI). (*)
 
 To understand more about it, see the section <a href="https://fastapi.tiangolo.com/benchmarks/" class="internal-link" target="_blank">Benchmarks</a>.
 
-## Dependencies { #dependencies }
+## Dependencies
 
 FastAPI depends on Pydantic and Starlette.
 
-### `standard` Dependencies { #standard-dependencies }
+### `standard` Dependencies
 
 When you install FastAPI with `pip install "fastapi[standard]"` it comes with the `standard` group of optional dependencies:
 
@@ -476,15 +476,15 @@ Used by FastAPI:
 * `fastapi-cli[standard]` - to provide the `fastapi` command.
     * This includes `fastapi-cloud-cli`, which allows you to deploy your FastAPI application to <a href="https://fastapicloud.com" class="external-link" target="_blank">FastAPI Cloud</a>.
 
-### Without `standard` Dependencies { #without-standard-dependencies }
+### Without `standard` Dependencies
 
 If you don't want to include the `standard` optional dependencies, you can install with `pip install fastapi` instead of `pip install "fastapi[standard]"`.
 
-### Without `fastapi-cloud-cli` { #without-fastapi-cloud-cli }
+### Without `fastapi-cloud-cli`
 
 If you want to install FastAPI with the standard dependencies but without the `fastapi-cloud-cli`, you can install with `pip install "fastapi[standard-no-fastapi-cloud-cli]"`.
 
-### Additional Optional Dependencies { #additional-optional-dependencies }
+### Additional Optional Dependencies
 
 There are some additional dependencies you might want to install.
 
@@ -498,6 +498,6 @@ Additional optional FastAPI dependencies:
 * <a href="https://github.com/ijl/orjson" target="_blank"><code>orjson</code></a> - Required if you want to use `ORJSONResponse`.
 * <a href="https://github.com/esnme/ultrajson" target="_blank"><code>ujson</code></a> - Required if you want to use `UJSONResponse`.
 
-## License { #license }
+## License
 
 This project is licensed under the terms of the MIT license.
index 8462e2bc1f63f77472f88bb956b5a7f6052bd9e0..56ffb9d364e9e736ba89bb7c78c680e1eb27af3e 100644 (file)
@@ -44,6 +44,8 @@ en_config_path: Path = en_docs_path / mkdocs_name
 site_path = Path("site").absolute()
 build_site_path = Path("site_build").absolute()
 
+header_with_permalink_pattern = re.compile(r"^(#{1,6}) (.+?)(\s*\{\s*#.*\s*\})\s*$")
+
 
 @lru_cache
 def is_mkdocs_insiders() -> bool:
@@ -154,9 +156,21 @@ index_sponsors_template = """
 """
 
 
+def remove_header_permalinks(content: str):
+    lines: list[str] = []
+    for line in content.split("\n"):
+        match = header_with_permalink_pattern.match(line)
+        if match:
+            hashes, title, *_ = match.groups()
+            line = f"{hashes} {title}"
+        lines.append(line)
+    return "\n".join(lines)
+
+
 def generate_readme_content() -> str:
     en_index = en_docs_path / "docs" / "index.md"
     content = en_index.read_text("utf-8")
+    content = remove_header_permalinks(content)  # remove permalinks from headers
     match_pre = re.search(r"</style>\n\n", content)
     match_start = re.search(r"<!-- sponsors -->", content)
     match_end = re.search(r"<!-- /sponsors -->", content)