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/en/docs/advanced/async-tests.md b/docs/en/docs/advanced/async-tests.md index c7ec5e9e29..06d474afc9 100644 --- a/docs/en/docs/advanced/async-tests.md +++ b/docs/en/docs/advanced/async-tests.md @@ -94,6 +94,7 @@ 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, for example, using a lifespan async context manager. 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](https://stackoverflow.com/questions/41584243/runtimeerror-task-attached-to-a-different-loop)), remember to instantiate objects that need an event loop only within async functions, e.g. an `@app.on_event("startup")` callback. /// diff --git a/docs_src/app_testing/tutorial003.py b/docs_src/app_testing/tutorial003.py new file mode 100644 index 0000000000..3ff87cb2a7 --- /dev/null +++ b/docs_src/app_testing/tutorial003.py @@ -0,0 +1,30 @@ +from contextlib import asynccontextmanager +from typing import Any + +from fastapi import FastAPI +from fastapi.testclient import TestClient + +# Use typing.Dict for compatibility with older Python versions +items: dict[str, Any] = {} + + +@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"} diff --git a/docs_src/app_testing/tutorial003_py310.py b/docs_src/app_testing/tutorial003_py310.py index ca6b45ce03..07bf7f2367 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}") diff --git a/tests/test_tutorial/test_testing/test_tutorial003.py b/tests/test_tutorial/test_testing/test_tutorial003.py index 196fc45559..b455bc949f 100644 --- a/tests/test_tutorial/test_testing/test_tutorial003.py +++ b/tests/test_tutorial/test_testing/test_tutorial003.py @@ -1,7 +1,11 @@ -import pytest +from docs_src.app_testing import tutorial003, tutorial003_py310 -def test_main(): - with pytest.warns(DeprecationWarning): - 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()