Migri is a simple async Python migration tool. You can use the CLI (run yourself or from a shell script) or import the exposed functions and run programatically. Currently supports PostgreSQL (asyncpg), SQLite (aiosqlite), and MySQL (aiomysql).
migri
is currently in alpha and although unlikely, the implementation may change
Using async database libraries is useful when a service/application is already using an async library. It's extra overhead to install a synchronous library just to run migrations. Practically speaking, though, there isn't much benefit to running migrations asynchronously since migrations must be applied synchronously. Besides, the number of migrations for a service is generally small.
pip install migri[mysql]
pip install migri[postgresql]
pip install migri[sqlite]
Create a migrations
directory and add your migrations. Migrations are applied in
lexicographical order (e.g. 0001_initial.sql
then 0002_add_user_data.py
and so on).
Currently .sql
and .py
files are supported. If you write a Python migration file,
ensure that it contains an async function migrate
. An instance of asyncpg's Connection
class will be passed into the function.
async def migrate(conn) -> bool:
await conn.execute("INSERT INTO categories (name) VALUES ($1)", "Animals")
return True
Run migri migrate
. Provide database credentials via arguments or environment variables:
--db-name
orDB_NAME
(required)--db-user
orDB_USER
--db-pass
orDB_PASS
--db-host
orDB_HOST
--db-port
orDB_PORT
Other options:
-d, --dialect
orDB_DIALECT
(mysql
,postgresql
,sqlite
, note that currently onlypostgresql
is supported. If not set,migri
will attempt to infer the dialect (and library to use) using the database port.)-l, --log-level
orLOG_LEVEL
(defaulterror
)
When you run migrate
, migri
will create a table called applied_migration
(if it
doesn't exist). This is how migri
tracks which migrations have already been applied.
If you want to test your migrations without applying them, you can use the dry run
flag: --dry-run
.
Unfortunately, dry run mode does not work with SQLite at this moment. If you want to try to get it to work, see the issue.
Dry run mode also doesn't work w/ MySQL because DDL statements implicitly commit.
Migri can be called with a shell script (e.g. when a container is starting) or you can apply migrations from your application:
from migri import apply_migrations, PostgreSQLConnection
async def migrate():
conn = PostgreSQLConnection(
"sampledb",
db_user="user",
db_pass="passpass",
db_host="localhost",
db_port=5432
)
async with conn:
await apply_migrations("migrations", conn)
- Set up local Python versions (e.g.
pyenv local 3.7.7 3.8.3
) - Run
docker-compose up
to start Postgresql. - Install nox with
pip install nox
. - Run
nox
.
Docstrings are formatted in the Sphinx format.
- Don't record empty migrations - warn user
- Add dry run mode for testing migrations
- Output migration results
- Test modules not found
- Test/handle incorrect migrate function signature (in migration Python files)
- Add colorful output 🍭 for enhanced readability
- Make error output more readable