diff --git a/docs/migration/v4.md b/docs/migration/v4.md index fc7587e..aeaf656 100644 --- a/docs/migration/v4.md +++ b/docs/migration/v4.md @@ -21,7 +21,7 @@ The function creates and manages its own **dedicated session** internally, yield user.balance += 100 # With a custom lock mode - async with lock_tables(session, [Order], mode=LockMode.EXCLUSIVE): + async with lock_tables(session=session, tables=[Order], mode=LockMode.EXCLUSIVE): await process_order(session, order_id) ``` @@ -35,6 +35,6 @@ The function creates and manages its own **dedicated session** internally, yield user.balance += 100 # With a custom lock mode - async with lock_tables(session_maker, [Order], mode=LockMode.EXCLUSIVE) as session: + async with lock_tables(session_maker=session_maker, tables=[Order], mode=LockMode.EXCLUSIVE) as session: await process_order(session, order_id) ``` diff --git a/docs/migration/v5.md b/docs/migration/v5.md new file mode 100644 index 0000000..3daf397 --- /dev/null +++ b/docs/migration/v5.md @@ -0,0 +1,147 @@ +# Migrating to v5.0 + +This page covers every breaking change introduced in **v5.0** and the steps required to update your code. + +--- + +## Database + +`db.py` is now the `db/` package, built around one object, [`Database`](../reference/db.md#fastapi_toolsets.db.Database), that owns the engine and sessionmaker. The free functions that took a `session_maker` you built and passed around yourself are gone from request-handling code; `Database` builds the sessionmaker for you. + +### `create_db_dependency` / `create_db_context` removed in favor of `Database` + +Build one `Database` with your URL (or an existing `engine=`), then use the instance directly as the FastAPI dependency, and `db.session()` for sessions outside request handlers. + +=== "Before (`v4`)" + + ```python + from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker + from fastapi_toolsets.db import create_db_dependency, create_db_context + + engine = create_async_engine("postgresql+asyncpg://...") + SessionLocal = async_sessionmaker(engine, expire_on_commit=False) + + get_db = create_db_dependency(session_maker=SessionLocal) + get_db_context = create_db_context(session_maker=SessionLocal) + + @app.get("/users") + async def list_users(session: AsyncSession = Depends(get_db)): + ... + + async def seed(): + async with get_db_context() as session: + ... + ``` + +=== "Now (`v5`)" + + ```python + from fastapi_toolsets.db import Database + + db = Database(url="postgresql+asyncpg://...") + + @app.get("/users") + async def list_users(session: AsyncSession = Depends(db)): + ... + + async def seed(): + async with db.session() as session: + ... + ``` + +Call `db.install(app)` to also commit before the response is sent (instead of in dependency teardown) and to dispose the engine on shutdown. See [the db module docs](../module/db.md#committing-before-the-response). + +### `get_transaction` renamed to `transaction` + +Same behavior (savepoint when already in a transaction, new transaction otherwise), new name, same import path. + +=== "Before (`v4`)" + + ```python + from fastapi_toolsets.db import get_transaction + + async with get_transaction(session=session): + session.add(model) + ``` + +=== "Now (`v5`)" + + ```python + from fastapi_toolsets.db import transaction + + async with transaction(session=session): + session.add(model) + ``` + +If you have a `Database` instance, `db.begin()` opens a session already inside a transaction: + +```python +async with db.begin() as session: + session.add(User(name="ada")) +``` + +### `lock_tables` is now also a `Database` method + +The free `lock_tables(session_maker, tables, ...)` function still exists for callers who manage their own session factory, but prefer `db.lock_tables(tables, ...)`, which drops the `session_maker` argument: + +=== "Before (`v4`)" + + ```python + from fastapi_toolsets.db import lock_tables, LockMode + + async with lock_tables(session_maker=session_maker, tables=[Order], mode=LockMode.EXCLUSIVE) as session: + await process_order(session, order_id) + ``` + +=== "Now (`v5`)" + + ```python + from fastapi_toolsets.db import LockMode + + async with db.lock_tables(tables=[Order], mode=LockMode.EXCLUSIVE) as session: + await process_order(session, order_id) + ``` + +### `create_database` and `cleanup_tables` moved to `fastapi_toolsets.db.testing` + +=== "Before (`v4`)" + + ```python + from fastapi_toolsets.db import create_database, cleanup_tables + ``` + +=== "Now (`v5`)" + + ```python + from fastapi_toolsets.db.testing import create_database, cleanup_tables + ``` + +## Fixtures + +### `get_obj_by_attr` / `get_field_by_attr` are now `FixtureRegistry` methods + +=== "Before (`v4`)" + + ```python + from fastapi_toolsets.fixtures import get_obj_by_attr, get_field_by_attr + + @fixtures.register(depends_on=["roles"]) + def users(): + admin_role = get_obj_by_attr(roles, "name", "admin") + return [User(id=1, username="alice", role_id=admin_role.id)] + ``` + +=== "Now (`v5`)" + + ```python + @fixtures.register(depends_on=["roles"]) + def users(): + admin_role = fixtures.obj("roles", "name", "admin") + return [User(id=1, username="alice", role_id=admin_role.id)] + ``` + +## Security + +The security module has been removed and moved to a dedicated python package: [`fastapi-multiauth`](https://github.com/d3vyce/fastapi-multiauth). + +Run `uv add fastapi-multiauth` and replace `from fastapi_toolsets.security import ...` with `from fastapi_multiauth import ...`. diff --git a/docs/module/cli.md b/docs/module/cli.md index c80a736..43d5b2a 100644 --- a/docs/module/cli.md +++ b/docs/module/cli.md @@ -24,7 +24,7 @@ Configure the CLI in your `pyproject.toml`: ```toml [tool.fastapi-toolsets] -cli = "myapp.cli:cli" # Custom Typer app +custom_cli = "myapp.cli:cli" # Custom Typer app fixtures = "myapp.fixtures:registry" # FixtureRegistry instance db_context = "myapp.db:db_context" # Async context manager for sessions ``` diff --git a/zensical.toml b/zensical.toml index d4cc6fe..5b501e7 100644 --- a/zensical.toml +++ b/zensical.toml @@ -121,7 +121,6 @@ Modules = [ {Models = "module/models.md"}, {Pytest = "module/pytest.md"}, {Schemas = "module/schemas.md"}, - {Security = "module/security.md"}, ] [[project.nav]] @@ -137,7 +136,6 @@ Reference = [ {Models = "reference/models.md"}, {Pytest = "reference/pytest.md"}, {Schemas = "reference/schemas.md"}, - {Security = "reference/security.md"}, ] [[project.nav]] @@ -147,6 +145,7 @@ Examples = [ [[project.nav]] Migration = [ + {"v5.0" = "migration/v5.md"}, {"v4.0" = "migration/v4.md"}, {"v3.0" = "migration/v3.md"}, {"v2.0" = "migration/v2.md"},