API Reference¶
Auto-generated API documentation from source code using mkdocstrings.
Testing¶
MigrationTestBase¶
Bases: MigrationSchemaMixin, MigrationConsistencyMixin, MigrationNamingMixin
Base class for database migration tests.
Inherit from this class and provide the following fixtures to get all five migration tests for free:
Required fixtures
migration_db_url: str— async DSN to the test database.orm_metadata: MetaData— SQLAlchemy metadata of your ORM models.
Auto-provided fixtures (override if needed):
- alembic_config — reads alembic.ini from the current directory.
- migration_engine — async engine with NullPool.
- isolated_migration_schema — unique schema per test, auto-dropped.
Optional class attributes
migration_diff_ignore_tables: list[str]— table names to exclude from schema diff and naming checks (e.g. auto-generated partition tables).allowed_index_prefixes,allowed_index_suffixes,allowed_fk_suffixes— override naming convention rules.
Example::
class TestMyMigrations(MigrationTestBase):
migration_diff_ignore_tables = ["events_partitioned_default"]
@pytest.fixture
def orm_metadata(self) -> MetaData:
return Base.metadata
isolated_migration_schema(migration_db_url)
async
¶
Create a unique PostgreSQL schema for this test run and drop it afterwards.
test_downgrade_all_the_way(alembic_config, migration_engine, isolated_migration_schema)
async
¶
Verify all migrations can be downgraded to base one by one.
test_migrations_up_to_date(alembic_config, migration_engine, isolated_migration_schema, orm_metadata)
async
¶
Verify the database schema after a full upgrade matches the SQLAlchemy ORM metadata.
test_naming_conventions(alembic_config, migration_engine, isolated_migration_schema)
async
¶
Verify indexes and foreign keys follow naming conventions after a full upgrade.
test_single_head_revision(alembic_config)
async
¶
Verify there is exactly one head revision (no unmerged branches).
test_stairway_upgrade_downgrade(alembic_config, migration_engine, isolated_migration_schema)
async
¶
Verify every migration can be applied and rolled back individually (stairway test).
For each revision in chronological order: 1. Upgrade to this revision. 2. Assert current revision matches. 3. Downgrade to the previous revision (or base). 4. Assert the downgrade succeeded. 5. Upgrade back before moving to the next step.
MigrationSchemaMixin¶
Provides the isolated_migration_schema fixture.
isolated_migration_schema(migration_db_url)
async
¶
Create a unique PostgreSQL schema for this test run and drop it afterwards.
MigrationConsistencyMixin¶
Core migration correctness tests.
test_downgrade_all_the_way(alembic_config, migration_engine, isolated_migration_schema)
async
¶
Verify all migrations can be downgraded to base one by one.
test_migrations_up_to_date(alembic_config, migration_engine, isolated_migration_schema, orm_metadata)
async
¶
Verify the database schema after a full upgrade matches the SQLAlchemy ORM metadata.
test_single_head_revision(alembic_config)
async
¶
Verify there is exactly one head revision (no unmerged branches).
test_stairway_upgrade_downgrade(alembic_config, migration_engine, isolated_migration_schema)
async
¶
Verify every migration can be applied and rolled back individually (stairway test).
For each revision in chronological order: 1. Upgrade to this revision. 2. Assert current revision matches. 3. Downgrade to the previous revision (or base). 4. Assert the downgrade succeeded. 5. Upgrade back before moving to the next step.
MigrationNamingMixin¶
Naming convention tests for database objects.
test_naming_conventions(alembic_config, migration_engine, isolated_migration_schema)
async
¶
Verify indexes and foreign keys follow naming conventions after a full upgrade.
Utilities¶
Migration utilities¶
Migration runner and schema isolation utilities.
run_alembic_upgrade(engine, alembic_config, target_schema='public', revision='head')
async
¶
Run alembic upgrade programmatically without spawning a subprocess.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
engine
|
AsyncEngine
|
Async SQLAlchemy engine. |
required |
alembic_config
|
Config
|
Alembic config object (typically from |
required |
target_schema
|
str
|
PostgreSQL schema to run migrations in. Defaults to |
'public'
|
revision
|
str
|
Target revision identifier. Defaults to |
'head'
|
Source code in alembic_gauntlet/utils/migrations.py
run_alembic_downgrade(engine, alembic_config, target_schema='public', revision='base')
async
¶
Run alembic downgrade programmatically without spawning a subprocess.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
engine
|
AsyncEngine
|
Async SQLAlchemy engine. |
required |
alembic_config
|
Config
|
Alembic config object. |
required |
target_schema
|
str
|
PostgreSQL schema to run migrations in. Defaults to |
'public'
|
revision
|
str
|
Target revision identifier. Defaults to |
'base'
|
Source code in alembic_gauntlet/utils/migrations.py
get_current_revision(engine, target_schema='public')
async
¶
Return the current Alembic revision for the given schema, or None if at base.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
engine
|
AsyncEngine
|
Async SQLAlchemy engine. |
required |
target_schema
|
str
|
PostgreSQL schema to inspect. Defaults to |
'public'
|
Source code in alembic_gauntlet/utils/migrations.py
get_all_revisions(alembic_config)
¶
Return all migration revision IDs in chronological order (base → head).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
alembic_config
|
Config
|
Alembic config object. |
required |
Source code in alembic_gauntlet/utils/migrations.py
create_isolated_migration_schema(migration_db_url)
async
¶
Create a unique PostgreSQL schema for one test run, yield it, then drop it.
Uses a dedicated engine so that schema creation and deletion do not interfere with the connection pool used by the migration engine.
Schema name format: test_mig_{8-char hex}.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
migration_db_url
|
str
|
Async DSN for the test database. |
required |
Yields:
| Type | Description |
|---|---|
AsyncGenerator[str, None]
|
The name of the freshly created schema. |
Source code in alembic_gauntlet/utils/migrations.py
Schema validation¶
Schema name validation utilities.
validate_schema_name(name, connection=None)
¶
Validate a PostgreSQL schema name to prevent SQL injection and ensure sanity.
Checks format, length, and optionally reserved words (requires a live connection).
Source code in alembic_gauntlet/utils/validation.py
Diff utilities¶
Schema diff filtering for migration consistency tests.
DEFAULT_IGNORE_TABLES = frozenset({'alembic_version'})
module-attribute
¶
is_ignored_diff_item(diff_item, ignore_tables)
¶
Return True if this diff item should be excluded from schema diff checks.
Filters out tables and their indexes that exist in the database but are absent from ORM metadata — for example, partition tables auto-created by PostgreSQL.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
diff_item
|
tuple
|
A single item from Alembic's |
required |
ignore_tables
|
frozenset[str]
|
Set of table names to skip. |
required |
Source code in alembic_gauntlet/utils/diff.py
Naming utilities¶
Database naming convention validation.
fetch_table_naming_results(sync_conn, schema)
¶
Fetch index and foreign key names for every table in the given schema.
The alembic_version table is always excluded.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sync_conn
|
Connection
|
Synchronous SQLAlchemy connection. |
required |
schema
|
str
|
PostgreSQL schema to inspect. |
required |
Returns:
| Type | Description |
|---|---|
dict[str, TableNamingResults]
|
Mapping of |
Source code in alembic_gauntlet/utils/naming.py
validate_naming_results(results, allowed_index_prefixes, allowed_index_suffixes, allowed_fk_suffixes)
¶
Assert that every index and foreign key follows naming conventions.
Index names must match at least one allowed prefix or one allowed suffix.
An optional trailing digit is accepted on suffixes to accommodate PostgreSQL
partition auto-naming (e.g. users_pkey1).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
results
|
dict[str, TableNamingResults]
|
Output of :func: |
required |
allowed_index_prefixes
|
list[str]
|
Prefixes an index name may start with (e.g. |
required |
allowed_index_suffixes
|
list[str]
|
Suffixes an index name may end with (e.g. |
required |
allowed_fk_suffixes
|
list[str]
|
Suffixes a foreign key name must end with (e.g. |
required |
Source code in alembic_gauntlet/utils/naming.py
Fixtures¶
Core fixtures¶
Standard pytest fixtures for Alembic migration testing.
alembic_config()
¶
Create an Alembic :class:~alembic.config.Config from alembic.ini.
Override this fixture in your test class to point to a different alembic.ini::
@pytest.fixture
def alembic_config(self) -> Config:
from pathlib import Path
from alembic.config import Config
ini = Path(__file__).parent.parent / "alembic.ini"
return Config(str(ini))
Source code in alembic_gauntlet/fixtures.py
migration_engine(migration_db_url)
async
¶
Async engine with :class:~sqlalchemy.pool.NullPool for migration tests.
NullPool prevents connection reuse between tests, which is important for schema isolation when running tests in parallel.
Requires the migration_db_url fixture to be provided.
Source code in alembic_gauntlet/fixtures.py
Exceptions¶
Exception classes for alembic-gauntlet.
EmptySchemaNameError
¶
Bases: SchemaValidationError
Schema name is empty.
InvalidSchemaNameError
¶
Bases: SchemaValidationError
Schema name has invalid format.
ReservedWordSchemaNameError
¶
Bases: SchemaValidationError
Schema name is a PostgreSQL reserved word.
SchemaNameTooLongError
¶
Bases: SchemaValidationError
Schema name exceeds the PostgreSQL maximum identifier length of 63 characters.
Contrib¶
Testcontainers¶
Optional migration_db_url fixture powered by testcontainers.
Import this fixture in your conftest.py to get a fully managed PostgreSQL
container without any external setup::
# tests/conftest.py
from alembic_gauntlet.contrib.testcontainers import migration_db_url # noqa: F401
The fixture has session scope, so the container starts once per test session.
Override migration_db_url in your own conftest to use a different database.
Requires the optional extra::
pip install "alembic-gauntlet[testcontainers]"
migration_db_url()
¶
Start a PostgreSQL 17 container and yield its async DSN.
The container is stopped automatically at the end of the test session.
Raises:
| Type | Description |
|---|---|
ImportError
|
If |