class Config(object):
"""Represent an Alembic configuration.
-
+
You can get at one of these by specifying the name of
an .ini file::
-
+
from alembic.config import Config
alembic_cfg = Config("/path/to/yourapp/alembic.ini")
-
+
With a :class:`.Config` object, you can then
run Alembic commands programmatically using the directives
in :mod:`alembic.command`.
-
+
"""
def __init__(self, file_, ini_section='alembic'):
self.config_file_name = file_
from. Defaults to ``alembic``, that is the ``[alembic]`` section
of the .ini file. This value is modified using the ``-n/--name``
option to the Alembic runnier.
-
+
"""
@util.memoized_property
def file_config(self):
"""Return the underlying :class:`ConfigParser` object.
-
+
Direct access to the .ini file is available here,
though the :meth:`.Config.get_section` and
:meth:`.Config.get_main_option`
def get_template_directory(self):
"""Return the directory where Alembic setup templates are found.
-
+
This method is used by the alembic ``init`` and ``list_templates``
commands.
-
+
"""
return os.path.join(package_dir, 'templates')
def get_section(self, name):
"""Return all the configuration options from a given .ini file section
as a dictionary.
-
+
"""
return dict(self.file_config.items(name))
+ def get_section_option(self, section, name, default=None):
+ """Return an option from the given section of the .ini file.
+
+ """
+ if not self.file_config.has_section(section):
+ util.err("No config file %r found, or file has no "
+ "'[%s]' section" %
+ (self.config_file_name, section))
+ if self.file_config.has_option(section, name):
+ return self.file_config.get(section, name)
+ else:
+ return default
+
def get_main_option(self, name, default=None):
"""Return an option from the 'main' section of the .ini file.
-
+
This defaults to being a key from the ``[alembic]``
section, unless the ``-n/--name`` flag were used to
indicate a different section.
-
+
"""
- if not self.file_config.has_section(self.config_ini_section):
- util.err("No config file %r found, or file has no "
- "'[%s]' section" %
- (self.config_file_name, self.config_ini_section))
- if self.file_config.has_option(self.config_ini_section, name):
- return self.file_config.get(self.config_ini_section, name)
- else:
- return default
+ return self.get_section_option(self.config_ini_section, name, default)
def main(argv):
"""The console runner function for Alembic."""
Mediates the relationship between an ``env.py`` environment script,
a :class:`.ScriptDirectory` instance, and a :class:`.DDLImpl` instance.
+
+ The :class:`.Context` is available via the :func:`.get_context` function,
+ though usually one would call the various module level functions
+ described here.
"""
def __init__(self, dialect, script, connection, fn,
if self.as_sql and not current_rev:
_version.create(self.connection)
log.info("Running %s %s -> %s", change.__name__, prev_rev, rev)
+ if self.as_sql:
+ self.impl.static_output("-- Running %s %s -> %s" %(change.__name__, prev_rev, rev))
change(**kw)
if not self.impl.transactional_ddl:
self._update_current_rev(prev_rev, rev)
"""Return True if the current migrations environment should have
an active database connection.
+ Currently, this is ``True`` or ``False`` depending
+ on the the ``--sql`` flag passed.
+
"""
return not _context_opts.get('as_sql', False)
def get_head_revision():
- """Return the value of the 'head' revision."""
+ """Return the hex identifier of the 'head' revision."""
return _script._as_rev_number("head")
def get_starting_revision_argument():
"""Return the 'starting revision' argument,
- if the revision was passed as start:end.
+ if the revision was passed using ``start:end``.
- This is only usable in "offline" mode.
+ This is only meaningful in "offline" mode.
+ Returns ``None`` if no value is available
+ or was configured.
"""
if _context is not None:
def get_revision_argument():
"""Get the 'destination' revision argument.
- This will be the target rev number. 'head'
- is translated into the actual version number
- as is 'base' which is translated to None.
+ This is typically the argument passed to the
+ ``upgrade`` or ``downgrade`` command, but can
+ be overridden via the ``destination_rev`` argument
+ passed to :func:`.configure`.
+
+ If
+ it was specified as ``head``, the actual
+ version number is returned; if specified
+ as ``base``, ``None`` is returned.
"""
return _script._as_rev_number(_context_opts['destination_rev'])
def get_tag_argument():
- """Return the value passed for the ``--tag`` argument, if any."""
+ """Return the value passed for the ``--tag`` argument, if any.
+
+ The ``--tag`` argument is not used directly by Alembic,
+ but is available for custom ``env.py`` configurations that
+ wish to use it; particularly for offline generation scripts
+ that wish to generate tagged filenames.
+
+ """
return _context_opts.get('tag', None)
def configure(
get_context().execute(sql)
def get_context():
- """Return the current :class:`.DefaultContext` object.
-
- This object is the entrypoint to dialect specific behavior.
+ """Return the current :class:`.Context` object.
Generally, env.py scripts should access the module-level functions
in :mod:`alebmic.context` to get at this object's functionality.
# This line sets up loggers basically.
fileConfig(config.config_file_name)
-# Produce a SQLAlchemy engine using the key/values
-# within the "alembic" section of the documentation,
-# other otherwise what config_ini_section points to.
-engine = engine_from_config(
- config.get_section(config.config_ini_section), prefix='sqlalchemy.')
-
# other values from the config, defined by the needs of env.py,
# can be acquired:
# ... etc.
# if we're running in --sql mode, do everything connectionless.
+# We only need a URL, not an Engine, thereby not even requiring
+# the DBAPI be installed, though an actual Engine would of course be fine as well.
if not context.requires_connection():
- context.configure(dialect_name=engine.name)
+ url = config.get_main_option("sqlalchemy.url")
+ context.configure(url=url)
context.run_migrations()
# otherwise we need to make a connection.
else:
+
+ # Produce a SQLAlchemy engine using the key/values
+ # within the "alembic" section of the documentation,
+ # other otherwise what config_ini_section points to.
+ engine = engine_from_config(
+ config.get_section(config.config_ini_section), prefix='sqlalchemy.')
+
connection = engine.connect()
context.configure(connection=connection, dialect_name=engine.name)
USE_TWOPHASE = False
-from alembic import options, context
+from alembic import context
from sqlalchemy import engine_from_config
import re
import sys
import logging
logging.fileConfig(options.config_file)
+# gather section names referring to different
+# databases.
db_names = options.get_main_option('databases')
+
+# set aside if we need engines or just URLs to do this.
+need_engine = context.requires_connection()
+
+# load up SQLAlchemy engines or URLs.
engines = {}
for name in re.split(r',\s*', db_names):
engines[name] = rec = {}
- rec['engine'] = engine = \
- engine_from_config(options.get_section(name),
+ if need_engine:
+ rec['engine'] = engine_from_config(context.config.get_section(name),
prefix='sqlalchemy.')
+ else:
+ rec['url'] = context.config.get_section_option(name, "sqlalchemy.url")
-
-if not context.requires_connection():
+# for the --sql use case, run migrations for each URL into
+# individual files.
+if not need_engine:
for name, rec in engines.items():
- # Write output to individual per-engine files.
file_ = "%s.sql" % name
sys.stderr.write("Writing output to %s\n" % file_)
context.configure(
- dialect_name=rec['engine'].name,
+ url=rec['url'],
output_buffer=file(file_, 'w')
)
context.run_migrations(engine=name)
+
+# for the direct-to-DB use case, start a transaction on all
+# engines, then run all migrations, then commit all transactions.
else:
for name, rec in engines.items():
engine = rec['engine']
be loaded from there.
"""
-from alembic import config, context
+from alembic import context
from paste.deploy import loadapp
import logging
# customize this section for non-standard engine configurations.
meta = __import__("%s.model.meta" % config['pylons.package']).model.meta
+
if not context.requires_connection():
context.configure(
dialect_name=meta.engine.name)
env.py Directives
=================
+The :mod:`alembic.context` module contains API features that are generally used within
+``env.py`` files.
+
.. autofunction:: sqlalchemy.engine.engine_from_config
-.. autofunction:: alembic.context.configure
-.. autofunction:: alembic.context.get_context
-.. autofunction:: alembic.context.execute
-.. autofunction:: alembic.context.requires_connection
-.. autofunction:: alembic.context.run_migrations
-Internals
-=========
+.. currentmodule:: alembic.context
-.. currentmodule:: alembic.command
+.. automodule:: alembic.context
+ :members:
Commands
---------
+=========
Alembic commands are all represented by functions in the :mod:`alembic.command`
package. They all accept the same style of usage, being sent
the :class:`~.alembic.config.Config` object as the first argument.
+.. currentmodule:: alembic.command
.. automodule:: alembic.command
:members:
:undoc-members:
-Misc
-----
+Configuration
+==============
+
+.. currentmodule:: alembic.config
+
.. automodule:: alembic.config
:members:
:undoc-members:
+Internals
+=========
+
.. automodule:: alembic.script
:members:
:undoc-members:
yet implemented.
-Generating SQL Scripts
-======================
+Generating SQL Scripts (a.k.a. "Offline Mode")
+==============================================
A major capability of Alembic is to generate migrations as SQL scripts, instead of running
-them against the database - this is also referred to as "offline" mode.
+them against the database - this is also referred to as *offline mode*.
This is a critical feature when working in large organizations
where access to DDL is restricted, and SQL scripts must be handed off to DBAs. Alembic makes
this easy via the ``--sql`` option passed to any ``upgrade`` or ``downgrade`` command. We
zip_safe=False,
install_requires=[
'SQLAlchemy>=0.6.0',
- 'Mako'
+ 'Mako',
+ # TODO: should this not be here if the env. is
+ # Python 2.7/3.2 ? not sure how this is supposed
+ # to be handled
+ 'argparse'
],
entry_points="""
""",