Skip to content

Migrating to v6.0

This page covers every breaking change introduced in v6.0 and the steps required to update your code.


Requirements

Python >=3.11 is still supported, and 3.15 is added. The minimum versions of these dependencies move up:

Package v5 v6
sqlalchemy[asyncio] >=2.0 >=2.1.2
fastapi >=0.100.0 >=0.142.0
opentelemetry-api not required >=1.44.0

SQLAlchemy 2.1 required

Upgrade SQLAlchemy before updating fastapi-toolsets, and follow SQLAlchemy's migration guide for your own code.

uv add "sqlalchemy[asyncio]>=2.1.2" "fastapi>=0.142.0"

No schema change is needed: the UUIDv7Mixin column still defaults to uuidv7().

opentelemetry-api is a dependency

The logger reads the current trace and span ids through opentelemetry-api, which is now installed with fastapi-toolsets. It does nothing until a tracer provider is configured. Forwarding log records to OpenTelemetry needs the otel extra (fastapi-toolsets[otel]).

Exceptions

Constraint violations answer 409/422 instead of 500

init_exceptions_handlers now handles IntegrityError. Unique, foreign key and exclusion violations return 409, not-null and check violations return 422, each with its own error_code (DB-409-UNIQUE, DB-422-NOTNULL, ...). Other integrity errors are still a 500. See Constraint violations.

Clients that treated these 500s as a signal need updating. To keep the previous behaviour, register your own IntegrityError handler after init_exceptions_handlers:

from sqlalchemy.exc import IntegrityError

app.add_exception_handler(IntegrityError, my_handler)

The commit middleware of db.install(app) also answers a failed commit through the app's handler for that error, where it used to end in a 500.

Logger

logger.py is now the logger/ package. configure_logging takes a LoggingConfig or a level, plus any of its fields as keyword arguments, and FastAPI applications call init_logging, which also adds the request logging middleware. See the logger module for the new features: request context, access log, trace correlation and the OpenTelemetry bridge.

fmt and logger_name removed

Records are rendered by ConsoleFormatter on a terminal and JsonFormatter elsewhere, so a format string no longer applies. configure_logging always configures the root logger, which every named logger propagates to, so logger_name is gone too.

from fastapi_toolsets.logger import configure_logging

configure_logging(level="DEBUG", fmt="%(levelname)s %(name)s %(message)s", logger_name="myapp")
from fastapi_toolsets.logger import configure_logging

configure_logging(level="DEBUG", style="console")

To keep a custom layout, subclass ConsoleFormatter and set it on your own handler, or add a handler with your logging.Formatter to the root logger next to the ones configure_logging installs.

Output moves from stdout to stderr

Log lines are written to stderr, leaving stdout to your program's output. Pass stream="stdout" to keep the previous behaviour:

configure_logging(stream="stdout")

New default line format

The console line changed from %(asctime)s - %(name)s - %(levelname)s - %(message)s to a shorter layout with milliseconds, the fields passed through extra=, and the request id:

18:00:59.934 INFO  myapp.auth  Flag submitted challenge_id=42 [2fd09820]

Outside a terminal, records are JSON objects, one per line. Tools parsing the previous format need updating, or set style="console" and datefmt="%Y-%m-%d %H:%M:%S" to come closer to it.

uvicorn's access log

init_logging replaces uvicorn's access log with one structured line per request. Pass access_log=False to keep uvicorn's.

Noisy third-party loggers capped at WARNING

asyncio, httpcore, httpx and urllib3 are held at WARNING whatever level you pass, so level="DEBUG" no longer shows their records. Pass quiet=() to let them through, or raise one logger with levels. See Configuration.

configure_logging(level="DEBUG", quiet=())

Records forwarded to OpenTelemetry when the otel extra is installed

With opentelemetry-instrumentation-logging installed, configure_logging adds a handler that emits every record to the OpenTelemetry logger provider. If your app already attaches its own LoggingHandler, records would be exported twice: drop yours, or pass otel=False. See Sending logs to OpenTelemetry.