diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 51ca24ba5..b1429a562 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -14,7 +14,7 @@ repos:
- id: end-of-file-fixer
- id: trailing-whitespace
- repo: https://github.com/astral-sh/ruff-pre-commit
- rev: v0.11.6
+ rev: v0.11.7
hooks:
- id: ruff
args:
diff --git a/docs/de/docs/how-to/custom-docs-ui-assets.md b/docs/de/docs/how-to/custom-docs-ui-assets.md
index ab8cd9f6b..f68902b99 100644
--- a/docs/de/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/de/docs/how-to/custom-docs-ui-assets.md
@@ -98,7 +98,7 @@ Sie können wahrscheinlich mit der rechten Maustaste auf jeden Link klicken und
Und **ReDoc** verwendet diese Datei:
-* `redoc.standalone.js`
+* `redoc.standalone.js`
Danach könnte Ihre Dateistruktur wie folgt aussehen:
@@ -129,14 +129,8 @@ Sie sollten eine sehr lange JavaScript-Datei für **ReDoc** sehen.
Sie könnte beginnen mit etwas wie:
```JavaScript
-/*!
- * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
- * -------------------------------------------------------------
- * Version: "2.0.0-rc.18"
- * Repo: https://github.com/Redocly/redoc
- */
-!function(e,t){"object"==typeof exports&&"object"==typeof m
-
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
diff --git a/docs/en/docs/how-to/custom-docs-ui-assets.md b/docs/en/docs/how-to/custom-docs-ui-assets.md
index f717c98fa..9d2238e4f 100644
--- a/docs/en/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/en/docs/how-to/custom-docs-ui-assets.md
@@ -98,7 +98,7 @@ You can probably right-click each link and select an option similar to `Save lin
And **ReDoc** uses the file:
-* `redoc.standalone.js`
+* `redoc.standalone.js`
After that, your file structure could look like:
@@ -129,14 +129,8 @@ You should see a very long JavaScript file for **ReDoc**.
It could start with something like:
```JavaScript
-/*!
- * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
- * -------------------------------------------------------------
- * Version: "2.0.0-rc.18"
- * Repo: https://github.com/Redocly/redoc
- */
-!function(e,t){"object"==typeof exports&&"object"==typeof m
-
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md
index 553546258..08f8ecbbc 100644
--- a/docs/en/docs/release-notes.md
+++ b/docs/en/docs/release-notes.md
@@ -7,6 +7,10 @@ hide:
## Latest Changes
+### Upgrades
+
+* ⬆️ Update ReDoc to version 2.x. PR [#9700](https://github.com/fastapi/fastapi/pull/9700) by [@joakimnordling](https://github.com/joakimnordling).
+
### Docs
* 📝 Remove unnecessary bullet from docs. PR [#13641](https://github.com/fastapi/fastapi/pull/13641) by [@Adamowoc](https://github.com/Adamowoc).
@@ -26,6 +30,8 @@ hide:
### Internal
+* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13656](https://github.com/fastapi/fastapi/pull/13656) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
+* ✅ Use `inline-snapshot` to support different Pydantic versions in the test suite. PR [#12534](https://github.com/fastapi/fastapi/pull/12534) by [@15r10nk](https://github.com/15r10nk).
* ⬆ Bump astral-sh/setup-uv from 5 to 6. PR [#13648](https://github.com/fastapi/fastapi/pull/13648) by [@dependabot[bot]](https://github.com/apps/dependabot).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13634](https://github.com/fastapi/fastapi/pull/13634) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
* ⬆ [pre-commit.ci] pre-commit autoupdate. PR [#13619](https://github.com/fastapi/fastapi/pull/13619) by [@pre-commit-ci[bot]](https://github.com/apps/pre-commit-ci).
diff --git a/docs/es/docs/how-to/custom-docs-ui-assets.md b/docs/es/docs/how-to/custom-docs-ui-assets.md
index 444cf167e..0a03ff330 100644
--- a/docs/es/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/es/docs/how-to/custom-docs-ui-assets.md
@@ -98,7 +98,7 @@ Probablemente puedas hacer clic derecho en cada enlace y seleccionar una opción
Y **ReDoc** utiliza el archivo:
-* `redoc.standalone.js`
+* `redoc.standalone.js`
Después de eso, tu estructura de archivos podría verse así:
@@ -129,14 +129,8 @@ Deberías ver un archivo JavaScript muy largo de **ReDoc**.
Podría comenzar con algo como:
```JavaScript
-/*!
- * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
- * -------------------------------------------------------------
- * Version: "2.0.0-rc.18"
- * Repo: https://github.com/Redocly/redoc
- */
-!function(e,t){"object"==typeof exports&&"object"==typeof m
-
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
diff --git a/docs/pt/docs/how-to/custom-docs-ui-assets.md b/docs/pt/docs/how-to/custom-docs-ui-assets.md
index 3adc7529e..b7de6c8bd 100644
--- a/docs/pt/docs/how-to/custom-docs-ui-assets.md
+++ b/docs/pt/docs/how-to/custom-docs-ui-assets.md
@@ -98,7 +98,7 @@ Você provavelmente pode clicar com o botão direito em cada link e selecionar u
E o **ReDoc** usa os arquivos:
-* `redoc.standalone.js`
+* `redoc.standalone.js`
Depois disso, sua estrutura de arquivos deve se parecer com:
@@ -129,14 +129,8 @@ Você deverá ver um arquivo JavaScript muito longo para o **ReDoc**.
Esse arquivo pode começar com algo como:
```JavaScript
-/*!
- * ReDoc - OpenAPI/Swagger-generated API Reference Documentation
- * -------------------------------------------------------------
- * Version: "2.0.0-rc.18"
- * Repo: https://github.com/Redocly/redoc
- */
-!function(e,t){"object"==typeof exports&&"object"==typeof m
-
+/*! For license information please see redoc.standalone.js.LICENSE.txt */
+!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("null")):
...
```
diff --git a/docs_src/custom_docs_ui/tutorial001.py b/docs_src/custom_docs_ui/tutorial001.py
index f7ceb0c2f..1cfcce19a 100644
--- a/docs_src/custom_docs_ui/tutorial001.py
+++ b/docs_src/custom_docs_ui/tutorial001.py
@@ -29,7 +29,7 @@ async def redoc_html():
return get_redoc_html(
openapi_url=app.openapi_url,
title=app.title + " - ReDoc",
- redoc_js_url="https://unpkg.com/redoc@next/bundles/redoc.standalone.js",
+ redoc_js_url="https://unpkg.com/redoc@2/bundles/redoc.standalone.js",
)
diff --git a/fastapi/openapi/docs.py b/fastapi/openapi/docs.py
index c2ec358d2..f181b43c1 100644
--- a/fastapi/openapi/docs.py
+++ b/fastapi/openapi/docs.py
@@ -188,7 +188,7 @@ def get_redoc_html(
It is normally set to a CDN URL.
"""
),
- ] = "https://cdn.jsdelivr.net/npm/redoc@next/bundles/redoc.standalone.js",
+ ] = "https://cdn.jsdelivr.net/npm/redoc@2/bundles/redoc.standalone.js",
redoc_favicon_url: Annotated[
str,
Doc(
diff --git a/requirements-tests.txt b/requirements-tests.txt
index 013b9a35a..f722825dd 100644
--- a/requirements-tests.txt
+++ b/requirements-tests.txt
@@ -10,7 +10,7 @@ anyio[trio] >=3.2.1,<5.0.0
PyJWT==2.8.0
pyyaml >=5.3.1,<7.0.0
passlib[bcrypt] >=1.7.2,<2.0.0
-inline-snapshot==0.19.3
+inline-snapshot>=0.21.1
# types
types-ujson ==5.10.0.20240515
types-orjson ==3.6.2
diff --git a/tests/test_application.py b/tests/test_application.py
index 5c62f5f6e..a7d50ea72 100644
--- a/tests/test_application.py
+++ b/tests/test_application.py
@@ -43,7 +43,7 @@ def test_redoc():
response = client.get("/redoc")
assert response.status_code == 200, response.text
assert response.headers["content-type"] == "text/html; charset=utf-8"
- assert "redoc@next" in response.text
+ assert "redoc@2" in response.text
def test_enum_status_code_response():
diff --git a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
index 30adadc8a..cef6f6630 100644
--- a/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
+++ b/tests/test_tutorial/test_cookie_param_models/test_tutorial002.py
@@ -5,7 +5,13 @@ from dirty_equals import IsDict
from fastapi.testclient import TestClient
from inline_snapshot import snapshot
-from tests.utils import needs_py39, needs_py310, needs_pydanticv1, needs_pydanticv2
+from tests.utils import (
+ needs_py39,
+ needs_py310,
+ needs_pydanticv1,
+ needs_pydanticv2,
+ pydantic_snapshot,
+)
@pytest.fixture(
@@ -59,8 +65,8 @@ def test_cookie_param_model_defaults(client: TestClient):
def test_cookie_param_model_invalid(client: TestClient):
response = client.get("/items/")
assert response.status_code == 422
- assert response.json() == snapshot(
- IsDict(
+ assert response.json() == pydantic_snapshot(
+ v2=snapshot(
{
"detail": [
{
@@ -71,9 +77,8 @@ def test_cookie_param_model_invalid(client: TestClient):
}
]
}
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
+ ),
+ v1=snapshot(
{
"detail": [
{
@@ -83,7 +88,7 @@ def test_cookie_param_model_invalid(client: TestClient):
}
]
}
- )
+ ),
)
@@ -144,18 +149,23 @@ def test_openapi_schema(client: TestClient):
"name": "fatebook_tracker",
"in": "cookie",
"required": False,
- "schema": IsDict(
- {
- "anyOf": [{"type": "string"}, {"type": "null"}],
- "title": "Fatebook Tracker",
- }
- )
- | IsDict(
- # TODO: remove when deprecating Pydantic v1
- {
- "type": "string",
- "title": "Fatebook Tracker",
- }
+ "schema": pydantic_snapshot(
+ v2=snapshot(
+ {
+ "anyOf": [
+ {"type": "string"},
+ {"type": "null"},
+ ],
+ "title": "Fatebook Tracker",
+ }
+ ),
+ v1=snapshot(
+ # TODO: remove when deprecating Pydantic v1
+ {
+ "type": "string",
+ "title": "Fatebook Tracker",
+ }
+ ),
),
},
{
diff --git a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
index aff070d74..cb8e8c224 100644
--- a/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
+++ b/tests/test_tutorial/test_custom_docs_ui/test_tutorial001.py
@@ -33,7 +33,7 @@ def test_swagger_ui_oauth2_redirect_html(client: TestClient):
def test_redoc_html(client: TestClient):
response = client.get("/redoc")
assert response.status_code == 200, response.text
- assert "https://unpkg.com/redoc@next/bundles/redoc.standalone.js" in response.text
+ assert "https://unpkg.com/redoc@2/bundles/redoc.standalone.js" in response.text
def test_api(client: TestClient):
diff --git a/tests/test_tutorial/test_sql_databases/test_tutorial002.py b/tests/test_tutorial/test_sql_databases/test_tutorial002.py
index 79e48c1c3..8a98f9a2d 100644
--- a/tests/test_tutorial/test_sql_databases/test_tutorial002.py
+++ b/tests/test_tutorial/test_sql_databases/test_tutorial002.py
@@ -4,7 +4,7 @@ import warnings
import pytest
from dirty_equals import IsDict, IsInt
from fastapi.testclient import TestClient
-from inline_snapshot import snapshot
+from inline_snapshot import Is, snapshot
from sqlalchemy import StaticPool
from sqlmodel import SQLModel, create_engine
from sqlmodel.main import default_registry
@@ -117,14 +117,14 @@ def test_crud_app(client: TestClient):
)
assert response.status_code == 200, response.text
assert response.json() == snapshot(
- {"name": "Dog Pond", "age": None, "id": hero_id}
+ {"name": "Dog Pond", "age": None, "id": Is(hero_id)}
)
# Get updated hero
response = client.get(f"/heroes/{hero_id}")
assert response.status_code == 200, response.text
assert response.json() == snapshot(
- {"name": "Dog Pond", "age": None, "id": hero_id}
+ {"name": "Dog Pond", "age": None, "id": Is(hero_id)}
)
# Delete a hero
diff --git a/tests/utils.py b/tests/utils.py
index 460c028f7..ae9543e3b 100644
--- a/tests/utils.py
+++ b/tests/utils.py
@@ -2,6 +2,7 @@ import sys
import pytest
from fastapi._compat import PYDANTIC_V2
+from inline_snapshot import Snapshot
needs_py39 = pytest.mark.skipif(sys.version_info < (3, 9), reason="requires python3.9+")
needs_py310 = pytest.mark.skipif(
@@ -9,3 +10,25 @@ needs_py310 = pytest.mark.skipif(
)
needs_pydanticv2 = pytest.mark.skipif(not PYDANTIC_V2, reason="requires Pydantic v2")
needs_pydanticv1 = pytest.mark.skipif(PYDANTIC_V2, reason="requires Pydantic v1")
+
+
+def pydantic_snapshot(
+ *,
+ v2: Snapshot,
+ v1: Snapshot, # TODO: remove v1 argument when deprecating Pydantic v1
+):
+ """
+ This function should be used like this:
+
+ >>> assert value == pydantic_snapshot(v2=snapshot(),v1=snapshot())
+
+ inline-snapshot will create the snapshots when pytest is executed for each versions of pydantic.
+
+ It is also possible to use the function inside snapshots for version-specific values.
+
+ >>> assert value == snapshot({
+ "data": "some data",
+ "version_specific": pydantic_snapshot(v2=snapshot(),v1=snapshot()),
+ })
+ """
+ return v2 if PYDANTIC_V2 else v1