def display_version(rev, context):
print "Current revision for %s: %s" % (
util.obfuscate_url_pw(
- context.get_context().connection.engine.url),
+ context.connection.engine.url),
script._get_rev(rev))
return []
"""Represent an Alembic configuration.
Within an ``env.py`` script, this is available
- via the :attr:`alembic.context.config` attribute::
+ via the :attr:`.EnvironmentContext.config` attribute,
+ which in turn is available at ``alembic.context``::
from alembic import context
:param ini_section: name of the main Alembic section within the
.ini file
:param output_buffer: optional file-like input buffer which
- will be passed to the :class:`.Context` - used to redirect
+ will be passed to the :class:`.MigrationContext` - used to redirect
access when using Alembic programmatically.
"""
return conn_col_default != rendered_metadata_default
def start_migrations(self):
- """A hook called when :meth:`.Context.run_migrations`
+ """A hook called when :meth:`.EnvironmentContext.run_migrations`
is called.
Implementations can set up per-migration-run state here.
equivalent, on the current connection context.
This is used in offline mode and typically
- via :func:`.context.begin_transaction`.
+ via :meth:`.EnvironmentContext.begin_transaction`.
"""
self.static_output("BEGIN;")
equivalent, on the current connection context.
This is used in offline mode and typically
- via :func:`.context.begin_transaction`.
+ via :meth:`.EnvironmentContext.begin_transaction`.
"""
self.static_output("COMMIT;")
_migration_context = None
_default_opts = None
+ config = None
+ """An instance of :class:`.Config` representing the
+ configuration file contents as well as other variables
+ set programmatically within it."""
+
+ script = None
+ """An instance of :class:`.ScriptDirectory` which provides
+ programmatic access to version files within the ``versions/``
+ directory.
+
+ """
+
def __init__(self, config, script, **kw):
self.config = config
self.script = script
what kind of "dialect" is in use. The second is to pass
an actual database connection, if one is required.
- If the :func:`.is_offline_mode` function returns ``True``,
+ If the :meth:`.is_offline_mode` function returns ``True``,
then no connection is needed here. Otherwise, the
``connection`` parameter should be present as an
instance of :class:`sqlalchemy.engine.base.Connection`.
script within a migration environment. It can be called
multiple times for an invocation. The most recent :class:`~sqlalchemy.engine.base.Connection`
for which it was called is the one that will be operated upon
- by the next call to :func:`.run_migrations`.
+ by the next call to :meth:`.run_migrations`.
General parameters:
``downgrades``.
:param alembic_module_prefix: When autogenerate refers to Alembic
- :mod:`alembic.op` constructs, this prefix will be used
+ :mod:`alembic.operations` constructs, this prefix will be used
(i.e. ``op.create_table``) Defaults to "``op.``".
Can be ``None`` to indicate no prefix.
to the migration functions.
This function requires that a :class:`.MigrationContext` has first been
- made available via :func:`.configure`.
+ made available via :meth:`.configure`.
"""
with Operations.context(self._migration_context):
def execute(self, sql):
"""Execute the given SQL using the current change context.
- The behavior of :func:`.context.execute` is the same
- as that of :func:`.op.execute`. Please see that
+ The behavior of :meth:`.execute` is the same
+ as that of :meth:`.Operations.execute`. Please see that
function's documentation for full detail including
caveats and limitations.
This function requires that a :class:`.MigrationContext` has first been
- made available via :func:`.configure`.
+ made available via :meth:`.configure`.
"""
self.migration_context.execute(sql)
If :meth:`.EnvironmentContext.configure` has not been called yet, raises
an exception.
- Generally, env.py scripts should access the module-level functions
- in :mod:`alebmic.context` to get at this object's functionality.
+ Generally, env.py scripts should access this via
+ the ``alembic.context`` object, which is an instance of
+ :class:`.MigrationContext` placed there for the duration
+ of the env.py script's usage.
"""
if self._migration_context is None:
"""Return the current 'bind'.
In "online" mode, this is the
- :class:`sqlalchemy.engine.Connection` currently being used
+ :class:`sqlalchemy.engine.base.Connection` currently being used
to emit SQL to the database.
This function requires that a :class:`.MigrationContext` has first been
Mediates the relationship between an ``env.py`` environment script,
a :class:`.ScriptDirectory` instance, and a :class:`.DefaultImpl` instance.
- The :class:`.MigrationContext` is available directly via the :func:`.get_context` function,
- though usually it is referenced behind the scenes by the various module level functions
- within the :mod:`alembic.context` module.
+ The :class:`.MigrationContext` that's established for a
+ duration of a migration command is available via the
+ :attr:`.EnvironmentContext.migration_context` datamember,
+ which is available at ``alembic.context``::
+
+ from alembic import context
+ migration_context = context.migration_context
"""
def __init__(self, dialect, connection, opts):
from contextlib import contextmanager
import alembic
-__all__ = sorted([
- 'alter_column',
- 'add_column',
- 'drop_column',
- 'drop_constraint',
- 'create_foreign_key',
- 'create_table',
- 'drop_table',
- 'drop_index',
- 'create_index',
- 'inline_literal',
- 'bulk_insert',
- 'rename_table',
- 'create_unique_constraint',
- 'create_check_constraint',
- 'get_context',
- 'get_bind',
- 'execute'])
+__all__ = ('Operations',)
class Operations(object):
"""Define high level migration operations.
e.g.::
- from alembic.op import add_column
+ from alembic import op
from sqlalchemy import Column, String
- add_column('organization',
+ op.add_column('organization',
Column('name', String())
)
"referenced" table and emit a second ALTER statement in order
to add the constraint separately::
- from alembic.op import add_column
+ from alembic import op
from sqlalchemy import Column, INTEGER, ForeignKey
- add_column('organization',
+ op.add_column('organization',
Column('account_id', INTEGER, ForeignKey('accounts.id'))
)
e.g.::
- from alembic.op import create_foreign_key
- create_foreign_key("fk_user_address", "address", "user", ["user_id"], ["id"])
+ from alembic import op
+ op.create_foreign_key("fk_user_address", "address", "user", ["user_id"], ["id"])
This internally generates a :class:`~sqlalchemy.schema.Table` object
containing the necessary columns, then generates a new
e.g.::
- from alembic.op import create_unique_constraint
- create_unique_constraint("uq_user_name", "user", ["name"])
+ from alembic import op
+ op.create_unique_constraint("uq_user_name", "user", ["name"])
This internally generates a :class:`~sqlalchemy.schema.Table` object
containing the necessary columns, then generates a new
e.g.::
- from alembic.op import create_check_constraint
+ from alembic import op
from sqlalchemy.sql import column, func
- create_check_constraint(
+ op.create_check_constraint(
"ck_user_name_len",
"user",
func.len(column('name')) > 5
metadata::
from sqlalchemy import INTEGER, VARCHAR, NVARCHAR, Column
- from alembic.op import create_table
+ from alembic import op
- create_table(
+ op.create_table(
'accounts',
Column('id', INTEGER, primary_key=True),
Column('name', VARCHAR(50), nullable=False),
e.g.::
- from alembic.op import create_index
- create_index('ik_test', 't1', ['foo', 'bar'])
+ from alembic import op
+ op.create_index('ik_test', 't1', ['foo', 'bar'])
"""
advanced types like dates may not be supported directly
by SQLAlchemy.
- See :func:`.op.execute` for an example usage of
- :func:`.inline_literal`.
+ See :meth:`.execute` for an example usage of
+ :meth:`.inline_literal`.
:param value: The value to render. Strings, integers, and simple
numerics should be supported. Other types like boolean,
with a connected database, use the "bind" available
from the context::
- from alembic.op import get_bind
- connection = get_bind()
+ from alembic import op
+ connection = op.get_bind()
Also note that any parameterized statement here *will not work*
in offline mode - INSERT, UPDATE and DELETE statements which refer
to literal values would need to render
- inline expressions. For simple use cases, the :func:`.inline_literal`
+ inline expressions. For simple use cases, the :meth:`.inline_literal`
function can be used for **rudimentary** quoting of string values.
- For "bulk" inserts, consider using :func:`~alembic.op.bulk_insert`.
+ For "bulk" inserts, consider using :meth:`.bulk_insert`.
For example, to emit an UPDATE statement which is equally
compatible with both online and offline mode::
from sqlalchemy.sql import table, column
from sqlalchemy import String
- from alembic.op import execute, inline_literal
+ from alembic import op
account = table('account',
column('name', String)
)
- execute(
+ op.execute(
account.update().\\
- where(account.c.name==inline_literal('account 1')).\\
- values({'name':inline_literal('account 2')})
+ where(account.c.name==op.inline_literal('account 1')).\\
+ values({'name':op.inline_literal('account 2')})
)
Note above we also used the SQLAlchemy :func:`sqlalchemy.sql.expression.table`
"""
return self.migration_context.impl.bind
-configure = Operations
\ No newline at end of file
in the migration environment. It is called exclusively
by the command functions in :mod:`alembic.command`.
- As ``env.py`` runs :func:`.context.configure_connection`,
- the connection environment should be set up first. This
- is typically achieved using the :func:`.context.opts`.
-
"""
util.load_python_file(self.dir, 'env.py')
return map_
def _rev_path(self, rev_id, message):
- slug = "_".join(_slug_re.findall(message or "")[0:20])
+ slug = "_".join(_slug_re.findall(message or "")[0:20]).lower()
filename = "%s.py" % (
self.file_template % {'rev':rev_id, 'slug':slug}
)
# A generic, single database configuration.
[alembic]
+# path to migration scripts
script_location = ${script_location}
+
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
sqlalchemy.url = driver://user:pass@localhost/dbname
# a multi-database configuration.
[alembic]
+# path to migration scripts
script_location = ${script_location}
+
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
databases = engine1, engine2
[engine1]
# a Pylons configuration.
[alembic]
+# path to migration scripts
script_location = ${script_location}
+
+# template used to generate migration files
+# file_template = %%(rev)s_%%(slug)s
+
pylons_config_file = ./development.ini
# that's it !
\ No newline at end of file
env.py Directives
=================
-The :mod:`alembic.context` module contains API features that are generally used within
+The :mod:`alembic.environment` module contains API features that are generally used within
``env.py`` files.
-The central object in use is the :class:`.Context` object. This object is
-made present when the ``env.py`` script calls upon the :func:`.configure`
+The central object in use is the :class:`.EnvironmentContext` object. This object is
+made present when the ``env.py`` script calls upon the :meth:`.EnvironmentContext.configure`
method for the first time. Before this function is called, there's not
yet any database connection or dialect-specific state set up, and those
functions which require this state will raise an exception when used,
-until :func:`.configure` is called successfully.
+until :meth:`.EnvironmentContext.configure` is called successfully.
.. autofunction:: sqlalchemy.engine.engine_from_config
-.. currentmodule:: alembic.context
+.. automodule:: alembic.environment
+ :members:
-.. automodule:: alembic.context
+.. automodule:: alembic.migration
:members:
+
Commands
=========
# The encoding of source files.
#source_encoding = 'utf-8'
+nitpicky = True
+
# The master toctree document.
master_doc = 'index'
# General information about the project.
project = u'Alembic'
-copyright = u'2010-2011, Mike Bayer'
+copyright = u'2010-2012, Mike Bayer'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the
SQLAlchemy as of version **0.6**, though with a limited featureset.
The latest version of SQLAlchemy within the **0.7** series is strongly recommended.
+Upgrading from Alembic 0.1 to 0.2
+=================================
+
+Alembic 0.2 has some reorganizations and features that might impact an existing 0.1
+installation. These include:
+
+* The ``alembic.op`` and ``alembic.context`` names are no longer Python modules,
+ and are instead objects placed at those names when migrations run. This
+ means an env.py script or migration script that tries to import from
+ the object will fail, such as ``from alembic.op import create_table``.
+ The imports used should now be of the form ``from alembic import context``
+ and ``from alembic import op``. The various methods associated with the
+ context and ops should be invoked from those names now, such as ``op.create_table()``.
+ The included files and the tutorial in 0.1 already did things this way,
+ though the examples for each ``op`` docstring did not. Hopefully most users
+ stuck with the tutorial convention, where the usage examples will
+ still work without change.
+
+* The naming convention for migration files is now customizable, and defaults
+ to the scheme "%(rev)s_%(slug)s", where "slug" is based on the message
+ added to the script. When Alembic reads one of these files, it looks
+ at a new variable named ``revision`` inside of the script to get at the
+ revision identifier. Scripts that use the new naming convention
+ will need to render this ``revision`` identifier inside the script,
+ so the ``script.py.mako`` file within an existing alembic environment
+ needs to have both ``revision`` and ``down_revision`` specified::
+
+ # revision identifiers, used by Alembic.
+ revision = ${repr(up_revision)}
+ down_revision = ${repr(down_revision)}
+
+ Existing scripts that use the 0.1 naming convention **don't have to be changed**,
+ unless you are renaming them. Alembic will fall back to pulling in the version
+ identifier from the filename if ``revision`` isn't present, as long as the
+ filename uses the old naming convention.
+
Community
=========
is derived from the :class:`.Context` object.
-.. automodule:: alembic.op
+.. automodule:: alembic.operations
:members:
README
script.py.mako
versions/
- 3512b954651e.py
- 2b1ae634e5cd.py
- 3adcc9a56557.py
+ 3512b954651e_add_account.py
+ 2b1ae634e5cd_add_order_id.py
+ 3adcc9a56557_rename_username_field.py
The directory includes these directories/files:
# A generic, single database configuration.
[alembic]
+ # path to migration scripts
script_location = %(here)s/alembic
+
+ # template used to generate migration files
+ # file_template = %%(rev)s_%%(slug)s
+
sqlalchemy.url = driver://user:pass@localhost/dbname
# Logging configuration
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
-The file is read using Python's :class:`ConfigParser.ConfigParser` object. The
+The file is read using Python's :class:`ConfigParser.SafeConfigParser` object. The
``%(here)s`` variable is provided as a substitution variable, which
can be used to produce absolute pathnames to directories and files, as we do above
with the path to the Alembic script location.
This is the only key required by Alembic in all cases. The generation
of the .ini file by the command ``alembic init alembic`` automatically placed the
directory name ``alembic`` here.
+* ``file_template`` - this is the naming scheme used to generate new migration files.
+ The value present is the default, so is commented out. The two tokens available
+ are ``%%(rev)s`` and ``%%(slug)s``, where ``%%(slug)s`` is a truncated string derived
+ from the revision message.
* ``sqlalchemy.url`` - A URL to connect to the database via SQLAlchemy. This key is in fact
only referenced within the ``env.py`` file that is specific to the "generic" configuration;
a file that can be customized by the developer. A multiple
With the environment in place we can create a new revision, using ``alembic revision``::
$ alembic revision -m "create account table"
- Generating /path/to/yourproject/alembic/versions/1975ea83b712.py...done
+ Generating /path/to/yourproject/alembic/versions/1975ea83b712_create_accoun
+ t_table.py...done
-A new file ``1975ea83b712.py`` is generated. Looking inside the file::
+A new file ``1975ea83b712_create_account_table.py`` is generated. Looking inside the file::
"""create account table
"""
- # downgrade revision identifier, used by Alembic.
+ # revision identifiers, used by Alembic.
+ revision = '1975ea83b712'
down_revision = None
from alembic import op
def downgrade():
pass
-The file contains some header information, a "downgrade revision identifier", an import
-of basic Alembic directives, and empty ``upgrade()`` and ``downgrade()`` functions. Our
+The file contains some header information, identifiers for the current revision
+and a "downgrade" revision, an import of basic Alembic directives,
+and empty ``upgrade()`` and ``downgrade()`` functions. Our
job here is to populate the ``upgrade()`` and ``downgrade()`` functions with directives that
will apply a set of changes to our database. Typically, ``upgrade()`` is required
while ``downgrade()`` is only needed if down-revision capability is desired, though it's
knows the correct order in which to apply migrations. When we create the next revision,
the new file's ``down_revision`` identifier would point to this one::
- # downgrade revision identifier, used by Alembic.
+ # revision identifiers, used by Alembic.
+ revision = 'ae1027a6acf'
down_revision = '1975ea83b712'
Every time Alembic runs an operation against the ``versions/`` directory, it reads all
def downgrade():
op.drop_table('account')
-:func:`.create_table` and :func:`.drop_table` are Alembic directives. Alembic provides
+:meth:`~.Operations.create_table` and :meth:`~.Operations.drop_table` are Alembic directives. Alembic provides
all the basic database migration operations via these directives, which are designed to be as simple and
minimalistic as possible;
there's no reliance upon existing table metadata for most of these directives. They draw upon
file::
$ alembic revision -m "Add a column"
- Generating /path/to/yourapp/alembic/versions/ae1027a6acf.py...done
+ Generating /path/to/yourapp/alembic/versions/ae1027a6acf.py_add_a_column.py...
+ done
Let's edit this file and add a new column to the ``account`` table::
"""
- # downgrade revision identifier, used by Alembic.
+ # revision identifiers, used by Alembic.
+ revision = 'ae1027a6acf'
down_revision = '1975ea83b712'
from alembic import op
has a `declarative base <http://www.sqlalchemy.org/docs/orm/extensions/declarative.html#synopsis>`_
in ``myapp.mymodel``. This base contains a :class:`~sqlalchemy.schema.MetaData` object which
contains :class:`~sqlalchemy.schema.Table` objects defining our database. We make sure this
-is loaded in ``env.py`` and then passed to :func:`.context.configure` via the
+is loaded in ``env.py`` and then passed to :meth:`.EnvironmentContext.configure` via the
``target_metadata`` argument. The ``env.py`` sample script already has a
variable declaration near the top for our convenience, where we replace ``None``
with our :class:`~sqlalchemy.schema.MetaData`. Starting with::
target_metadata = Base.metadata
If we look later in the script, down in ``run_migrations_online()``,
-we can see the directive passed to :func:`.context.configure`::
+we can see the directive passed to :meth:`.EnvironmentContext.configure`::
def run_migrations_online():
engine = engine_from_config(
Autogenerate can *optionally* detect:
* Change of column type. This will occur if you set ``compare_type=True``
- on :func:`.context.configure`. The feature works well in most cases,
+ on :meth:`.EnvironmentContext.configure`. The feature works well in most cases,
but is off by default so that it can be tested on the target schema
first. It can also be customized by passing a callable here; see the
function's documentation for details.
* Change of server default. This will occur if you set
- ``compare_server_default=True`` on :func:`.context.configure`.
+ ``compare_server_default=True`` on :meth:`.EnvironmentContext.configure`.
This feature works well for simple cases but cannot always produce
accurate results. The Postgresql backend will actually invoke
the "detected" and "metadata" values against the database to
Users of the ``--sql`` option are encouraged to hack their ``env.py`` files to suit their
needs. The ``env.py`` script as provided is broken into two sections: ``run_migrations_online()``
and ``run_migrations_offline()``. Which function is run is determined at the bottom of the
-script by reading :func:`.context.is_offline_mode`, which basically determines if the
+script by reading :meth:`.EnvironmentContext.is_offline_mode`, which basically determines if the
``--sql`` flag was enabled.
For example, a multiple database configuration may want to run through each
-database and set the output of the migrations to different named files - the :func:`.context.configure`
+database and set the output of the migrations to different named files - the :meth:`.EnvironmentContext.configure`
function accepts a parameter ``output_buffer`` for this purpose. Below we illustrate
this within the ``run_migrations_offline()`` function::