diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ec863f9c..7aa121c81 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,9 @@ jobs: PYTHONDEVMODE: 1 - name: Test FastAPI/Blacksheep/Sanic Examples run: | - PYTHONPATH=$DEST_FASTAPI uv run --frozen pytest $PYTEST_ARGS $DEST_FASTAPI/_tests.py + PYTHONPATH=$DEST_FASTAPI uv run --frozen tortoise -c config.TORTOISE_ORM migrate + PYTHONPATH=$DEST_FASTAPI uv run --frozen pytest $PYTEST_ARGS_SEQ $DEST_FASTAPI/_tests.py + rm -f $DEST_FASTAPI/db.sqlite3 PYTHONPATH=$DEST_BLACKSHEEP uv run --frozen pytest $PYTEST_ARGS $DEST_BLACKSHEEP/_tests.py PYTHONPATH=$DEST_SANIC uv run --frozen pytest $PYTEST_ARGS $DEST_SANIC/_tests.py env: @@ -67,6 +69,7 @@ jobs: DEST_SANIC: examples/sanic PYTHONDEVMODE: 1 PYTEST_ARGS: "-n auto --cov=tortoise --cov-append --cov-branch --tb=native -q" + PYTEST_ARGS_SEQ: "--cov=tortoise --cov-append --cov-branch --tb=native -q" - name: Test Comprehensive Migrations Example run: | cd examples/comprehensive_migrations_project diff --git a/examples/fastapi/_tests.py b/examples/fastapi/_tests.py index a26d15afe..fb4980c8e 100644 --- a/examples/fastapi/_tests.py +++ b/examples/fastapi/_tests.py @@ -1,7 +1,6 @@ # mypy: no-disallow-untyped-decorators # pylint: disable=E0611,E0401 import multiprocessing -import os from collections.abc import AsyncGenerator from concurrent.futures import ProcessPoolExecutor from contextlib import asynccontextmanager @@ -13,11 +12,10 @@ from asgi_lifespan import LifespanManager from httpx import ASGITransport, AsyncClient -from tortoise.contrib.test import MEMORY_SQLITE +from tortoise.contrib.test import truncate_all_models from tortoise.fields.data import JSON_LOADS from tortoise.timezone import UTC, localtime -os.environ["DB_URL"] = MEMORY_SQLITE try: from config import register_orm from main import app @@ -42,7 +40,6 @@ def anyio_backend() -> str: @asynccontextmanager async def client_manager(app, base_url="http://test", **kw) -> ClientManagerType: - app.state.testing = True async with LifespanManager(app): transport = ASGITransport(app=app) async with AsyncClient(transport=transport, base_url=base_url, **kw) as c: @@ -52,6 +49,7 @@ async def client_manager(app, base_url="http://test", **kw) -> ClientManagerType @pytest.fixture(scope="module") async def client() -> ClientManagerType: async with client_manager(app) as c: + await truncate_all_models() yield c @@ -62,6 +60,7 @@ async def client_east() -> ClientManagerType: async with client_manager(app_east) as c: ctx = app_east.state._tortoise_context with ctx: # Enter context to make it current via contextvar + await truncate_all_models() yield c diff --git a/examples/fastapi/config.py b/examples/fastapi/config.py index 824527bbc..989c80c08 100644 --- a/examples/fastapi/config.py +++ b/examples/fastapi/config.py @@ -1,12 +1,16 @@ import os from functools import partial +from pathlib import Path from tortoise.config import AppConfig, DBUrlConfig, TortoiseConfig from tortoise.contrib.fastapi import RegisterTortoise +BASE_DIR = Path(__file__).resolve().parent +DEFAULT_DB_URL = f"sqlite://{BASE_DIR / 'db.sqlite3'}" + # Single source of truth for Tortoise ORM configuration TORTOISE_ORM = TortoiseConfig( - connections={"default": DBUrlConfig(url=os.getenv("DB_URL", "sqlite://db.sqlite3"))}, + connections={"default": DBUrlConfig(url=os.getenv("DB_URL", DEFAULT_DB_URL))}, apps={ "models": AppConfig( models=["models"], diff --git a/examples/fastapi/main.py b/examples/fastapi/main.py index 97a3ca7f3..dd50b486b 100644 --- a/examples/fastapi/main.py +++ b/examples/fastapi/main.py @@ -1,50 +1,21 @@ # pylint: disable=E0611,E0401 -import os from collections.abc import AsyncGenerator from contextlib import asynccontextmanager +from config import register_orm from fastapi import FastAPI from routers import router as users_router -from examples.fastapi.config import register_orm -from tortoise import Tortoise -from tortoise.backends.base.config_generator import generate_config -from tortoise.contrib.fastapi import RegisterTortoise, tortoise_exception_handlers +from tortoise.contrib.fastapi import tortoise_exception_handlers @asynccontextmanager -async def lifespan_test(app: FastAPI) -> AsyncGenerator[None, None]: - config = generate_config( - os.getenv("TORTOISE_TEST_DB", "sqlite://:memory:"), - app_modules={"models": ["models"]}, - testing=True, - connection_label="models", - ) - async with RegisterTortoise( - app=app, - config=config, - generate_schemas=True, - _create_db=True, - ): +async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: + async with register_orm(app): # db connected yield # app teardown # db connections closed - await Tortoise._drop_databases() - - -@asynccontextmanager -async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: - if getattr(app.state, "testing", None): - async with lifespan_test(app) as _: - yield - else: - # app startup - async with register_orm(app): - # db connected - yield - # app teardown - # db connections closed app = FastAPI( diff --git a/examples/fastapi/main_custom_timezone.py b/examples/fastapi/main_custom_timezone.py index d6e9629d1..403f22298 100644 --- a/examples/fastapi/main_custom_timezone.py +++ b/examples/fastapi/main_custom_timezone.py @@ -9,9 +9,6 @@ @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]: - # app startup - # Disable global fallback since this is the secondary app in tests - # (main app already uses global fallback). Context is stored in app.state. async with register_orm( app, use_tz=True,