From ea42ebda809a06108115dbed1c010ac7e5e7ef1d Mon Sep 17 00:00:00 2001 From: Frank Hoffmann Date: Mon, 28 Apr 2025 09:13:56 +0200 Subject: [PATCH 1/6] =?UTF-8?q?=E2=9C=85=20Use=20`inline-snapshot`=20to=20?= =?UTF-8?q?support=20different=20Pydantic=20versions=20in=20the=20test=20s?= =?UTF-8?q?uite=20(#12534)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: svlandeg Co-authored-by: Sofie Van Landeghem --- requirements-tests.txt | 2 +- .../test_tutorial002.py | 48 +++++++++++-------- .../test_sql_databases/test_tutorial002.py | 6 +-- tests/utils.py | 23 +++++++++ 4 files changed, 56 insertions(+), 23 deletions(-) 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_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_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 From 419917297738c6ee2cb68ddf9f9cb2f5ec61df2c Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Apr 2025 07:14:30 +0000 Subject: [PATCH 2/6] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 553546258..d606d2eef 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -26,6 +26,7 @@ hide: ### Internal +* ✅ 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). From 8fa56b46a16859aaa6dd9d3eef140ef0682253f4 Mon Sep 17 00:00:00 2001 From: Joakim Nordling Date: Mon, 28 Apr 2025 21:31:44 +0300 Subject: [PATCH 3/6] =?UTF-8?q?=E2=AC=86=EF=B8=8F=20Update=20ReDoc=20to=20?= =?UTF-8?q?version=202.x=20(#9700)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: svlandeg Co-authored-by: Sebastián Ramírez Co-authored-by: Sofie Van Landeghem --- docs/de/docs/how-to/custom-docs-ui-assets.md | 12 +++--------- docs/en/docs/how-to/custom-docs-ui-assets.md | 12 +++--------- docs/es/docs/how-to/custom-docs-ui-assets.md | 12 +++--------- docs/pt/docs/how-to/custom-docs-ui-assets.md | 12 +++--------- docs_src/custom_docs_ui/tutorial001.py | 2 +- fastapi/openapi/docs.py | 2 +- tests/test_application.py | 2 +- .../test_custom_docs_ui/test_tutorial001.py | 2 +- 8 files changed, 16 insertions(+), 40 deletions(-) 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/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/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_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): From 4025751afb7e5403cbc944a49b2fdc8a02cee2bd Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Apr 2025 18:32:06 +0000 Subject: [PATCH 4/6] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index d606d2eef..31f35431f 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). From 26dc148cb91f9ec679b7cf1a74f5a6d6747e7e00 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 28 Apr 2025 20:37:31 +0200 Subject: [PATCH 5/6] =?UTF-8?q?=E2=AC=86=20[pre-commit.ci]=20pre-commit=20?= =?UTF-8?q?autoupdate=20(#13656)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.11.6 → v0.11.7](https://github.com/astral-sh/ruff-pre-commit/compare/v0.11.6...v0.11.7) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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: From 699717cf7fa51f7f9555efec82cae040020c8cb1 Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 28 Apr 2025 18:37:55 +0000 Subject: [PATCH 6/6] =?UTF-8?q?=F0=9F=93=9D=20Update=20release=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [skip ci] --- docs/en/docs/release-notes.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/en/docs/release-notes.md b/docs/en/docs/release-notes.md index 31f35431f..08f8ecbbc 100644 --- a/docs/en/docs/release-notes.md +++ b/docs/en/docs/release-notes.md @@ -30,6 +30,7 @@ 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).