CLI & Fixture Reference
pytest-mrt has two interfaces:
mrtCLI — analysis, fixing, and reporting without a databasemrtpytest fixture — dynamic verification against a real database
Command overview
| Command | What it does | Needs DB? |
|---|---|---|
mrt check <dir> |
Static analysis — 26 risk patterns | No |
mrt fix <file> |
Auto-generate missing or broken downgrade() | No |
mrt report <dir> |
HTML safety report of entire migration history | No |
mrt explain <file> |
AI explanation in plain English | No (needs API key) |
mrt version |
Show installed version | No |
mrtCLI — static analysis, runs without a databasemrtpytest fixture — dynamic verification, runs migrations against a real database
CLI: mrt check
Scans migration files for dangerous patterns. Fast, no database needed.
Finding your versions directory
It's where your migration files (.py files with revision = '...') live.
your-project/
├── alembic.ini
└── migrations/
├── env.py
└── versions/ ← this is what you pass to mrt check
├── 001_create_users.py
├── 002_add_email.py
└── 003_drop_phone.py
Options
| Option | Description | Default |
|---|---|---|
--strict |
Also fail on warnings, not just errors | Off |
Exit codes
| Code | Meaning |
|---|---|
0 |
No problems found |
1 |
One or more errors (or warnings with --strict) |
Use the exit code in CI to fail the pipeline automatically.
Example output
Rollback Risk Analysis
╭──────────┬─────────────────────────────┬─────────┬─────────────────────────────────────╮
│ Revision │ Pattern │ Sev │ Message │
├──────────┼─────────────────────────────┼─────────┼─────────────────────────────────────┤
│ 003 │ DROP COLUMN in upgrade │ error │ Column dropped — data permanently │
│ │ │ │ lost on rollback │
├──────────┼─────────────────────────────┼─────────┼─────────────────────────────────────┤
│ 004 │ No-op downgrade │ error │ downgrade() does nothing │
├──────────┼─────────────────────────────┼─────────┼─────────────────────────────────────┤
│ 005 │ INDEX without CONCURRENTLY │ warning │ Locks table during index build │
╰──────────┴─────────────────────────────┴─────────┴─────────────────────────────────────╯
2 error(s), 1 warning(s)
When there are no problems:
CLI: mrt version
Pytest fixture: mrt
The mrt fixture is the main interface for dynamic testing. Add mrt as a parameter to any test function and it becomes available automatically — no import needed.
Setup (required)
The fixture needs to know where your alembic.ini is and which database to use. Configure this in conftest.py:
# conftest.py
import os
from pytest_mrt import MRTConfig
def pytest_configure(config):
config._mrt_config = MRTConfig(
alembic_ini="alembic.ini",
db_url=os.environ.get("TEST_DATABASE_URL", "sqlite:///test.db"),
)
mrt.assert_all_reversible()
Tests every migration in your project, in order. This is the recommended starting point.
What it does for each revision:
- Seeds real rows into all existing tables
- Runs
alembic upgradeto that revision - Runs
alembic downgrade -1 - Checks the schema is exactly the same as before
- Checks all seeded rows are still there
If anything fails, the test fails with a detailed message:
FAILED: Some migrations are not safely reversible:
revision 003:
- Table 'users': 3/3 rows lost after rollback
mrt.check_revision(revision_id)
Tests a single revision. Returns a result object you can inspect.
def test_new_migration(mrt):
result = mrt.check_revision("abc1234")
# Simple pass/fail
assert result.passed, result.failure_summary()
def test_with_details(mrt):
result = mrt.check_revision("abc1234")
if not result.passed:
print(result.failures) # list of failure strings
print(result.revision) # the revision ID
pytest.fail(result.failure_summary())
Where to find the revision ID:
Open any migration file and look at the top:
# migrations/versions/003_drop_phone.py
revision = 'abc1234' # ← this is the revision ID
down_revision = 'xyz789'
mrt.assert_reversible(revision_id)
Like check_revision() but raises a pytest failure directly instead of returning a result.
Manual control
For custom scenarios where you want to control each step:
def test_custom_scenario(mrt):
# Move to a specific state
mrt.upgrade("abc1234")
# Run downgrade
mrt.downgrade()
# Check data integrity
mrt.assert_data_intact()
MRTConfig reference
from pytest_mrt import MRTConfig
MRTConfig(
alembic_ini="alembic.ini",
# Required.
# Path to your alembic.ini file, relative to where you run pytest.
# Usually this is in your project root.
db_url="postgresql://localhost/myapp_test",
# Required.
# Database URL for the test database.
# NEVER use your production database URL here.
# Supported: postgresql://, sqlite:///
seed_rows=3,
# Optional. Default: 3.
# Number of rows inserted per table before each rollback test.
# Higher values catch more edge cases but make tests slower.
)