Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ Install only the extras you need:
```bash
uv add "fastapi-toolsets[cli]"
uv add "fastapi-toolsets[metrics]"
uv add "fastapi-toolsets[security]"
uv add "fastapi-toolsets[pytest]"
```

Expand All @@ -57,7 +56,6 @@ uv add "fastapi-toolsets[all]"

### Optional

- **Security**: Composable authentication sources (`BearerTokenAuth`, `CookieAuth`, `APIKeyHeaderAuth`, `MultiAuth`) with HMAC-signed cookies and OAuth 2.0 / OIDC helpers
- **CLI**: Django-like command-line interface with fixture management and custom commands support
- **Metrics**: Prometheus metrics endpoint with provider/collector registry
- **Pytest Helpers**: Async test client, database session management, `pytest-xdist` support, and table cleanup utilities
Expand Down
2 changes: 0 additions & 2 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ Install only the extras you need:
```bash
uv add "fastapi-toolsets[cli]"
uv add "fastapi-toolsets[metrics]"
uv add "fastapi-toolsets[security]"
uv add "fastapi-toolsets[pytest]"
```

Expand All @@ -57,7 +56,6 @@ uv add "fastapi-toolsets[all]"

### Optional

- **Security**: Composable authentication sources (`BearerTokenAuth`, `CookieAuth`, `APIKeyHeaderAuth`, `MultiAuth`) with HMAC-signed cookies and OAuth 2.0 / OIDC helpers
- **CLI**: Django-like command-line interface with fixture management and custom commands support
- **Metrics**: Prometheus metrics endpoint with provider/collector registry
- **Pytest Helpers**: Async test client, database session management, `pytest-xdist` support, and table cleanup utilities
Expand Down
4 changes: 2 additions & 2 deletions docs/migration/v4.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
```

Expand All @@ -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)
```
147 changes: 147 additions & 0 deletions docs/migration/v5.md
Original file line number Diff line number Diff line change
@@ -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 ...`.
2 changes: 1 addition & 1 deletion docs/module/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
Loading
Loading