From 6cb4454b98aa194d41bee65f8626a0347551084d Mon Sep 17 00:00:00 2001 From: Areeb455 <141515705+Areeb455@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:13:15 +0000 Subject: [PATCH 1/4] docs: migrate testing tutorial from on_event to lifespan --- docs/en/docs/advanced/async-tests.md | 2 +- docs_src/app_testing/tutorial003_py310.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index cefb1d1841..23745b5ce3 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -94,6 +94,6 @@ As the testing function is now asynchronous, you can now also call (and `await`) /// tip -If you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using MongoDB's MotorClient), remember to instantiate objects that need an event loop only within async functions, e.g. an `@app.on_event("startup")` callback. +If you encounter a `RuntimeError: Task attached to a different loop` when integrating asynchronous function calls in your tests (e.g. when using MongoDB's MotorClient), remember to instantiate objects that need an event loop only within async functions, for example, using a lifespan async context manager. /// diff --git a/docs_src/app_testing/tutorial003_py310.py b/docs_src/app_testing/tutorial003_py310.py index ca6b45ce03..45f6f678c6 100644 --- a/docs_src/app_testing/tutorial003_py310.py +++ b/docs_src/app_testing/tutorial003_py310.py @@ -1,15 +1,19 @@ +from contextlib import asynccontextmanager + from fastapi import FastAPI from fastapi.testclient import TestClient -app = FastAPI() - items = {} -@app.on_event("startup") -async def startup_event(): +@asynccontextmanager +async def lifespan(app: FastAPI): items["foo"] = {"name": "Fighters"} items["bar"] = {"name": "Tenders"} + yield + + +app = FastAPI(lifespan=lifespan) @app.get("/items/{item_id}") @@ -21,4 +25,4 @@ def test_read_items(): with TestClient(app) as client: response = client.get("/items/foo") assert response.status_code == 200 - assert response.json() == {"name": "Fighters"} + assert response.json() == {"name": "Fighters"} \ No newline at end of file From 473d68bd631459650f5b161988515e4badb3b2e3 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Sat, 21 Feb 2026 22:18:51 +0000 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=8E=A8=20Auto=20format?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs_src/app_testing/tutorial003_py310.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs_src/app_testing/tutorial003_py310.py b/docs_src/app_testing/tutorial003_py310.py index 45f6f678c6..07bf7f2367 100644 --- a/docs_src/app_testing/tutorial003_py310.py +++ b/docs_src/app_testing/tutorial003_py310.py @@ -25,4 +25,4 @@ def test_read_items(): with TestClient(app) as client: response = client.get("/items/foo") assert response.status_code == 200 - assert response.json() == {"name": "Fighters"} \ No newline at end of file + assert response.json() == {"name": "Fighters"} From bde1624566c299afbc2b3c469198cd405e5c06c5 Mon Sep 17 00:00:00 2001 From: Areeb455 <141515705+Areeb455@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:01:38 +0000 Subject: [PATCH 3/4] docs: migrate to lifespan and update associated tests --- docs_src/app_testing/tutorial003.py | 28 +++++++++++++++++++ .../test_testing/test_tutorial003.py | 5 ++-- 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 docs_src/app_testing/tutorial003.py diff --git a/docs_src/app_testing/tutorial003.py b/docs_src/app_testing/tutorial003.py new file mode 100644 index 0000000000..45f6f678c6 --- /dev/null +++ b/docs_src/app_testing/tutorial003.py @@ -0,0 +1,28 @@ +from contextlib import asynccontextmanager + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +items = {} + + +@asynccontextmanager +async def lifespan(app: FastAPI): + items["foo"] = {"name": "Fighters"} + items["bar"] = {"name": "Tenders"} + yield + + +app = FastAPI(lifespan=lifespan) + + +@app.get("/items/{item_id}") +async def read_items(item_id: str): + return items[item_id] + + +def test_read_items(): + with TestClient(app) as client: + response = client.get("/items/foo") + assert response.status_code == 200 + assert response.json() == {"name": "Fighters"} \ No newline at end of file diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py index 196fc45559..bbadb296bb 100644 --- a/tests/test_tutorial/test_testing/test_tutorial003.py +++ b/tests/test_tutorial/test_testing/test_tutorial003.py @@ -1,7 +1,6 @@ import pytest - def test_main(): - with pytest.warns(DeprecationWarning): - from docs_src.app_testing.tutorial003_py310 import test_read_items + from docs_src.app_testing.tutorial003_py310 import test_read_items test_read_items() + From 5aa97a1776491347988100a7ee779cbb2f538bae Mon Sep 17 00:00:00 2001 From: Areeb455 <141515705+Areeb455@users.noreply.github.com> Date: Sat, 21 Feb 2026 23:24:23 +0000 Subject: [PATCH 4/4] test: explicit imports for 100% coverage and mypy compliance --- check_params.py | 7 +++++++ docs_src/app_testing/tutorial003.py | 6 ++++-- .../test_tutorial/test_testing/test_tutorial003.py | 13 +++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) create mode 100644 check_params.py diff --git a/check_params.py b/check_params.py new file mode 100644 index 0000000000..df8719546d --- /dev/null +++ b/check_params.py @@ -0,0 +1,7 @@ +from decimal import Decimal + +from fastapi import Query + + +def create_item(price: Decimal = Query(..., max_digits=5, decimal_places=2)): + return {"price": price} diff --git a/docs_src/app_testing/tutorial003.py b/docs_src/app_testing/tutorial003.py index 45f6f678c6..3ff87cb2a7 100644 --- a/docs_src/app_testing/tutorial003.py +++ b/docs_src/app_testing/tutorial003.py @@ -1,9 +1,11 @@ from contextlib import asynccontextmanager +from typing import Any from fastapi import FastAPI from fastapi.testclient import TestClient -items = {} +# Use typing.Dict for compatibility with older Python versions +items: dict[str, Any] = {} @asynccontextmanager @@ -25,4 +27,4 @@ def test_read_items(): with TestClient(app) as client: response = client.get("/items/foo") assert response.status_code == 200 - assert response.json() == {"name": "Fighters"} \ No newline at end of file + assert response.json() == {"name": "Fighters"} diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py index bbadb296bb..b455bc949f 100644 --- a/tests/test_tutorial/test_testing/test_tutorial003.py +++ b/tests/test_tutorial/test_testing/test_tutorial003.py @@ -1,6 +1,11 @@ -import pytest +from docs_src.app_testing import tutorial003, tutorial003_py310 -def test_main(): - from docs_src.app_testing.tutorial003_py310 import test_read_items - test_read_items() +def test_tutorial003(): + # This covers the base version (tutorial003.py) + tutorial003.test_read_items() + + +def test_tutorial003_py310(): + # This covers the modern version (tutorial003_py310.py) + tutorial003_py310.test_read_items()