Alembic wrapper#
Alembic is great but it has a configuration problem. While you web application config is probably one or more python files and parameters loaded from environment variables and other sources, Alembic needs a static alembic.ini
file. You are suppose to edit the almost-undocumented env.py
file to customize it to your application.
The Alembic
wrapper class aims to simplify that set up so you can just use your application config, without any more config files to maintain. The actual database migrations are still handled by Alembic so you get exactly the same functionality.
Set up#
The Alembic()
class require two arguments: A SQLAlchemy()
instance and the path of the folder that will contain the migrations.
from sqla_wrapper import Alembic, SQLAlchemy
db = SQLAlchemy(…)
alembic = Alembic(db, "db/migrations")
If the migrations folder doesn’t exists, it will be created.
CLI integrations#
The only downside is that you can’t use the alembic
command-line tool anymore. Instead, all the usual Alembic command are be available as methods of the wrapper instance and you need to integrate them with your framework/application CLI.
Is easier than it sounds, specially because the wrapper comes with one-line methods to extend Click (the CLI used by Flask by default) and Proper CLI (arguably, the best CLI ever made).
Integrating with Flask Click#
from flask import Flask
db = SQLAlchemy(…)
alembic = Alembic(…)
app = Flask(__name__)
app.cli.add_command(alembic.get_flask_cli("db"))
Integrating with Click#
import click
db = SQLAlchemy(…)
alembic = Alembic(…)
@click.group()
def cli():
pass
cli.add_command(alembic.get_click_cli("db"))
Integrating with Proper CLI#
from proper_cli import Cli
db = SQLAlchemy(…)
alembic = Alembic(…)
class Manage(Cli):
db = alembic.get_proper_cli("db")
cli = Manage()
API#
For a more in-depth understanding of these methods and the extra options, you can read the documentation for the Alembic config.
Provide an Alembic environment and migration API.
For a more in-depth understanding of these methods and the extra options, you can read the documentation for the Alembic config.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
db |
SQLAlchemy
|
A |
required |
path |
StrPath
|
Path to the migrations folder. |
'db/migrations'
|
**options |
Other alembic options |
{}
|
revision(message, *, empty=False, parent='head')
#
Create a new revision. Auto-generate operations by comparing models and database.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
message |
str
|
Revision message. |
required |
empty |
bool
|
Generate just an empty migration file, not the operations. |
False
|
parent |
str
|
Parent revision of this new revision. |
'head'
|
upgrade(target='head', *, sql=False, **kwargs)
#
Run migrations to upgrade database.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
target |
str
|
Revision target or “from:to” range if |
'head'
|
sql |
bool
|
Don’t emit SQL to database, dump to standard output instead. |
False
|
kwargs |
Optional arguments. If these are passed, they are sent directly
to the |
{}
|
downgrade(target='-1', *, sql=False, **kwargs)
#
Run migrations to downgrade database.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
target |
str
|
Revision target as an integer relative to the current
state (e.g.: “-1”), or as a “from:to” range if |
'-1'
|
sql |
bool
|
Don’t emit SQL to database, dump to standard output instead. |
False
|
kwargs |
Optional arguments.
If these are passed, they are sent directly
to the |
{}
|
get_history(*, start=None, end=None)
#
Get the list of revisions in chronological order. You can optionally specify the range of revisions to return.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
start |
str | None
|
From this revision (including it.) |
None
|
end |
str | None
|
To this revision (including it.) |
None
|
history(*, verbose=False, start='base', end='heads')
#
Print the list of revisions in chronological order. You can optionally specify the range of revisions to return.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
verbose |
bool
|
If |
False
|
start |
str | None
|
Optional starting revision (including it.) |
'base'
|
end |
str | None
|
Optional end revision (including it.) |
'heads'
|
stamp(target='head', *, sql=False, purge=False)
#
Set the given revision in the revision table. Don’t run migrations.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
target |
str
|
The target revision; “head” by default. |
'head'
|
sql |
bool
|
Don’t emit SQL to the database, dump to the standard output instead. |
False
|
purge |
bool
|
Delete all entries in the version table before stamping. |
False
|
get_current()
#
Get the last revision applied.
current(verbose=False)
#
Print the latest revision(s) applied.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
verbose |
bool
|
If |
False
|
get_head()
#
Get the latest revision.
head(verbose=False)
#
Print the latest revision.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
verbose |
bool
|
If |
False
|
init(path)
#
Creates a new migration folder
with a script.py.mako
template file. It doesn’t fail if the
folder or file already exists.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
path |
StrPath
|
Target folder. |
required |
create_all()
#
Create all the tables from the current models and stamp the latest revision without running any migration.
rev_id()
#
Generate a unique id for a revision.
By default this uses alembic.util.rev_id
. Override this
method to change it.