0.7.0
Released: November 24, 2014
-
[feature] [versioning] The "multiple heads / branches" feature has now landed. This is
by far the most significant change Alembic has seen since its inception;
while the workflow of most commands hasn't changed, and the format
of version files and thealembic_version
table are unchanged as well,
a new suite of features opens up in the case where multiple version
files refer to the same parent, or to the "base". Merging of
branches, operating across distinct named heads, and multiple
independent bases are now all supported. The feature incurs radical
changes to the internals of versioning and traversal, and should be
treated as "beta mode" for the next several subsequent releases
within 0.7.References: #167
-
[feature] [versioning] In conjunction with support for multiple independent bases, the
specific version directories are now also configurable to include
multiple, user-defined directories. When multiple directories exist,
the creation of a revision file with no down revision requires
that the starting directory is indicated; the creation of subsequent
revisions along that lineage will then automatically use that
directory for new files.References: #124
-
[feature] [operations] [sqlite] Added "move and copy" workflow, where a table to be altered is copied to
a new one with the new structure and the old one dropped, is now
implemented for SQLite as well as all database backends in general
using the newOperations.batch_alter_table()
system. This
directive provides a table-specific operations context which gathers
column- and constraint-level mutations specific to that table, and
at the end of the context creates a new table combining the structure
of the old one with the given changes, copies data from old table to new,
and finally drops the old table,
renaming the new one to the existing name. This is required for
fully featured SQLite migrations, as SQLite has very little support for the
traditional ALTER directive. The batch directive
is intended to produce code that is still compatible with other databases,
in that the "move and copy" process only occurs for SQLite by default,
while still providing some level of sanity to SQLite's
requirement by allowing multiple table mutation operations to
proceed within one "move and copy" as well as providing explicit
control over when this operation actually occurs. The "move and copy"
feature may be optionally applied to other backends as well, however
dealing with referential integrity constraints from other tables must
still be handled explicitly.References: #21
-
[commands] [feature] Relative revision identifiers as used with
alembic upgrade
,
alembic downgrade
andalembic history
can be combined with
specific revisions as well, e.g.alembic upgrade ae10+3
, to produce
a migration target relative to the given exact version. -
[bug] [commands] The
alembic revision
command accepts the--sql
option to
suit some very obscure use case where therevision_environment
flag is set up, so thatenv.py
is run whenalembic revision
is run even though autogenerate isn't specified. As this flag is
otherwise confusing, error messages are now raised if
alembic revision
is invoked with both--sql
and
--autogenerate
or with--sql
without
revision_environment
being set.References: #248
-
[autogenerate] [bug] [postgresql] Added a rule for Postgresql to not render a "drop unique" and "drop index"
given the same name; for now it is assumed that the "index" is the
implicit one Postgreql generates. Future integration with
new SQLAlchemy 1.0 features will improve this to be more
resilient.References: #247
-
[autogenerate] [bug] A change in the ordering when columns and constraints are dropped;
autogenerate will now place the "drop constraint" calls before
the "drop column" calls, so that columns involved in those constraints
still exist when the constraint is dropped.References: #247
-
[commands] [feature] New commands added:
alembic show
,alembic heads
and
alembic merge
. Also, a new option--verbose
has been
added to several informational commands, such asalembic history
,
alembic current
,alembic branches
, andalembic heads
.
alembic revision
also contains several new options used
within the new branch management system. The output of commands has
been altered in many cases to support new fields and attributes;
thehistory
command in particular now returns it's "verbose" output
only if--verbose
is sent; without this flag it reverts to it's
older behavior of short line items (which was never changed in the docs). -
[changed] [commands] The
--head_only
option to thealembic current
command is
deprecated; thecurrent
command now lists just the version numbers
alone by default; use--verbose
to get at additional output. -
[config] [feature] Added new argument
Config.config_args
, allows a dictionary
of replacement variables to be passed which will serve as substitution
values when an API-producedConfig
consumes the.ini
file. Pull request courtesy Noufal Ibrahim. -
[bug] [oracle] The Oracle dialect sets "transactional DDL" to False by default,
as Oracle does not support transactional DDL.References: #245
-
[autogenerate] [bug] Fixed a variety of issues surrounding rendering of Python code that
contains unicode literals. The first is that the "quoted_name" construct
that SQLAlchemy uses to represent table and column names as well
as schema names does notrepr()
correctly on Py2K when the value
contains unicode characters; therefore an explicit stringification is
added to these. Additionally, SQL expressions such as server defaults
were not being generated in a unicode-safe fashion leading to decode
errors if server defaults contained non-ascii characters.References: #243
-
[bug] [operations] The
Operations.add_column()
directive will now additionally emit
the appropriateCREATE INDEX
statement if the
~sqlalchemy.schema.Column
object specifiesindex=True
.
Pull request courtesy David Szotten.References: #174
-
[feature] [operations] The
~sqlalchemy.schema.Table
object is now returned when
theOperations.create_table()
method is used. ThisTable
is suitable for use in subsequent SQL operations, in particular
theOperations.bulk_insert()
operation.References: #205
-
[autogenerate] [feature] Indexes and unique constraints are now included in the
EnvironmentContext.configure.include_object
hook.
Indexes are sent with type"index"
and unique constraints with
type"unique_constraint"
.References: #203
-
[autogenerate] [bug] Bound parameters are now resolved as "literal" values within the
SQL expression inside of a CheckConstraint(), when rendering the SQL
as a text string; supported for SQLAlchemy 0.8.0 and forward.References: #219
-
[autogenerate] [bug] Added a workaround for SQLAlchemy issue #3023 (fixed in 0.9.5) where
a column that's part of an explicit PrimaryKeyConstraint would not
have its "nullable" flag set to False, thus producing a false
autogenerate. Also added a related correction to MySQL which will
correct for MySQL's implicit server default of '0' when a NULL integer
column is turned into a primary key column.References: #199
-
[autogenerate] [bug] [mysql] Repaired issue related to the fix for #208 and others; a composite
foreign key reported by MySQL would cause a KeyError as Alembic
attempted to remove MySQL's implicitly generated indexes from the
autogenerate list.References: #240
-
[autogenerate] [bug] If the "alembic_version" table is present in the target metadata,
autogenerate will skip this also. Pull request courtesy
Dj Gilcrease.References: #28
-
[autogenerate] [bug] The
EnvironmentContext.configure.version_table
andEnvironmentContext.configure.version_table_schema
arguments are now honored during the autogenerate process, such that
these names will be used as the "skip" names on both the database
reflection and target metadata sides.References: #77
-
[autogenerate] [changed] The default value of the
EnvironmentContext.configure.user_module_prefix
parameter is no longer the same as the SQLAlchemy prefix.
When omitted, user-defined types will now use the__module__
attribute of the type class itself when rendering in an
autogenerated module.References: #229
-
[bug] [templates] Revision files are now written out using the
'wb'
modifier to
open()
, since Mako reads the templates with'rb'
, thus preventing
CRs from being doubled up as has been observed on windows. The encoding
of the output now defaults to 'utf-8', which can be configured using
a newly added config file parameteroutput_encoding
.References: #234
-
[bug] [operations] Added support for use of the
~sqlalchemy.sql.elements.quoted_name
construct when using theschema
argument within operations. This
allows a name containing a dot to be fully quoted, as well as to
provide configurable quoting on a per-name basis.References: #230
-
[autogenerate] [bug] [postgresql] Added a routine by which the Postgresql Alembic dialect inspects
the server default of INTEGER/BIGINT columns as they are reflected
during autogenerate for the patternnextval(<name>...)
containing
a potential sequence name, then queriespg_catalog
to see if this
sequence is "owned" by the column being reflected; if so, it assumes
this is a SERIAL or BIGSERIAL column and the server default is
omitted from the column reflection as well as any kind of
server_default comparison or rendering, along with an INFO message
in the logs indicating this has taken place. This allows SERIAL/BIGSERIAL
columns to keep the SEQUENCE from being unnecessarily present within
the autogenerate operation.References: #73
-
[autogenerate] [bug] The system by which autogenerate renders expressions within
a~sqlalchemy.schema.Index
, theserver_default
of~sqlalchemy.schema.Column
, and the
existing_server_default
of
Operations.alter_column()
has been overhauled to anticipate
arbitrary SQLAlchemy SQL constructs, such asfunc.somefunction()
,
cast()
,desc()
, and others. The system does not, as might
be preferred, render the full-blown Python expression as originally
created within the application's source code, as this would be exceedingly
complex and difficult. Instead, it renders the SQL expression against
the target backend that's subject to the autogenerate, and then
renders that SQL inside of a~sqlalchemy.sql.expression.text()
construct as a literal SQL string. This approach still has the
downside that the rendered SQL construct may not be backend-agnostic
in all cases, so there is still a need for manual intervention in that
small number of cases, but overall the majority of cases should work
correctly now. Big thanks to Carlos Rivera for pull requests and
support on this. -
[feature] SQLAlchemy's testing infrastructure is now used to run tests.
This system supports both nose and pytest and opens the way
for Alembic testing to support any number of backends, parallel
testing, and 3rd party dialect testing. -
[changed] [compatibility] Minimum SQLAlchemy version is now 0.7.6, however at least
0.8.4 is strongly recommended. The overhaul of the test suite
allows for fully passing tests on all SQLAlchemy versions
from 0.7.6 on forward. -
[bug] [operations] The "match" keyword is not sent to
ForeignKeyConstraint
byOperations.create_foreign_key()
when SQLAlchemy 0.7 is in use;
this keyword was added to SQLAlchemy as of 0.8.0.