Skip to content

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 sqla_wrapper.SQLAlchemy instance.

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 sql=True. “head” by default.

'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 upgrade() functions within each revision file. To use, modify the script.py.makotemplate file so that the upgrade() functions can accept arguments.

{}

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 sql=True. “-1” by default.

'-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 downgrade() functions within each revision file. To use, modify the script.py.mako template file so that the downgrade() functions can accept arguments.

{}

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 True, shows also the path and the docstring of each revision file.

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 True, shows also the path and the docstring of the revision file.

False

get_head() #

Get the latest revision.

head(verbose=False) #

Print the latest revision.

Parameters:

Name Type Description Default
verbose bool

If True, shows also the path and the docstring of the revision file.

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.

get_proper_cli() #

get_click_cli(name='db') #

get_flask_cli(name='db') #