from os import path
-__version__ = '0.4.3'
+__version__ = '0.5.0'
package_dir = path.abspath(path.dirname(__file__))
from alembic import util
from alembic.ddl import impl
from sqlalchemy.types import NULLTYPE, Integer
-from sqlalchemy import schema as sa_schema, sql
+from sqlalchemy import schema as sa_schema
from contextlib import contextmanager
import alembic
schema=schema
)
+ @util._with_legacy_names([('name', 'new_column_name')])
def alter_column(self, table_name, column_name,
nullable=None,
server_default=False,
- name=None,
+ new_column_name=None,
type_=None,
autoincrement=None,
existing_type=None,
or :class:`~sqlalchemy.schema.DefaultClause` to indicate
an alteration to the column's default value.
Set to ``None`` to have the default removed.
- :param name: Optional; specify a string name here to
+ :param new_column_name: Optional; specify a string name here to
indicate the new name within a column rename operation.
+
+ .. versionchanged:: 0.5.0
+ The ``name`` parameter is now named ``new_column_name``.
+ The old name will continue to function for backwards
+ compatibility.
+
:param ``type_``: Optional; a :class:`~sqlalchemy.types.TypeEngine`
type object to specify a change to the column's type.
For SQLAlchemy types that also indicate a constraint (i.e.
self.impl.alter_column(table_name, column_name,
nullable=nullable,
server_default=server_default,
- name=name,
+ name=new_column_name,
type_=type_,
schema=schema,
autoincrement=autoincrement,
self._table(name, **kw)
)
- def create_index(self, name, tablename, columns, schema=None, **kw):
+ def create_index(self, name, table_name, columns, schema=None, **kw):
"""Issue a "create index" instruction using the current
migration context.
op.create_index('ik_test', 't1', ['foo', 'bar'])
:param name: name of the index.
- :param tablename: name of the owning table.
+ :param table_name: name of the owning table.
+
+ .. versionchanged:: 0.5.0
+ The ``tablename`` parameter is now named ``table_name``.
+ As this is a positional argument, the old name is no
+ longer present.
+
:param columns: a list of string column names in the
table.
:param schema: Optional schema name to operate within.
"""
self.impl.create_index(
- self._index(name, tablename, columns, schema=schema, **kw)
+ self._index(name, table_name, columns, schema=schema, **kw)
)
- def drop_index(self, name, tablename=None, schema=None):
+ @util._with_legacy_names([('tablename', 'table_name')])
+ def drop_index(self, name, table_name=None, schema=None):
"""Issue a "drop index" instruction using the current
migration context.
-
e.g.::
drop_index("accounts")
:param name: name of the index.
- :param tablename: name of the owning table. Some
+ :param table_name: name of the owning table. Some
backends such as Microsoft SQL Server require this.
+
+ .. versionchanged:: 0.5.0
+ The ``tablename`` parameter is now named ``table_name``.
+ The old name will continue to function for backwards
+ compatibility.
+
:param schema: Optional schema name to operate within.
.. versionadded:: 0.4.0
# need a dummy column name here since SQLAlchemy
# 0.7.6 and further raises on Index with no columns
self.impl.drop_index(
- self._index(name, tablename, ['x'], schema=schema)
+ self._index(name, table_name, ['x'], schema=schema)
)
- def drop_constraint(self, name, tablename, type_=None, schema=None, type=None):
+ @util._with_legacy_names([("type", "type_")])
+ def drop_constraint(self, name, table_name, type_=None, schema=None):
"""Drop a constraint of the given name, typically via DROP CONSTRAINT.
:param name: name of the constraint.
- :param tablename: tablename.
+ :param table_name: table name.
+
+ .. versionchanged:: 0.5.0
+ The ``tablename`` parameter is now named ``table_name``.
+ As this is a positional argument, the old name is no
+ longer present.
+
:param ``type_``: optional, required on MySQL. can be
'foreignkey', 'primary', 'unique', or 'check'.
- .. versionadded:: 0.4.2 the parameter is now named ``type_``.
+ .. versionchanged:: 0.5.0
+ The ``type`` parameter is now named ``type_``. The old name
``type`` will remain for backwards compatibility.
.. versionadded:: 0.3.6 'primary' qualfier to enable
dropping of MySQL primary key constraints.
- :param type: deprecated, use ``type_``.
-
- .. versionchanged:: 0.4.2
-
:param schema: Optional schema name to operate within.
.. versionadded:: 0.4.0
"""
- if type and type_ is None:
- type_ = type
- t = self._table(tablename, schema=schema)
+ t = self._table(table_name, schema=schema)
types = {
- 'foreignkey':lambda name:sa_schema.ForeignKeyConstraint(
+ 'foreignkey': lambda name: sa_schema.ForeignKeyConstraint(
[], [], name=name),
- 'primary':sa_schema.PrimaryKeyConstraint,
- 'unique':sa_schema.UniqueConstraint,
- 'check':lambda name:sa_schema.CheckConstraint("", name=name),
- None:sa_schema.Constraint
+ 'primary': sa_schema.PrimaryKeyConstraint,
+ 'unique': sa_schema.UniqueConstraint,
+ 'check': lambda name: sa_schema.CheckConstraint("", name=name),
+ None: sa_schema.Constraint
}
try:
const = types[type_]
import os
import textwrap
from sqlalchemy.engine import url
-from sqlalchemy import util as sqla_util
import imp
import warnings
import re
import inspect
-import time
-import random
import uuid
+from sqlalchemy.util import format_argspec_plus, update_wrapper
class CommandError(Exception):
pass
def __repr__(self):
return "immutabledict(%s)" % dict.__repr__(self)
+
+
+
+
+
+def _with_legacy_names(translations):
+ def decorate(fn):
+ spec = inspect.getargspec(fn)
+ metadata = dict(target='target', fn='fn')
+ metadata.update(format_argspec_plus(spec, grouped=False))
+
+ has_keywords = bool(spec[2])
+
+ if not has_keywords:
+ metadata['args'] += ", **kw"
+ metadata['apply_kw'] += ", **kw"
+
+ def go(*arg, **kw):
+ names = set(kw).difference(spec[0])
+ for oldname, newname in translations:
+ if oldname in kw:
+ kw[newname] = kw.pop(oldname)
+ names.discard(oldname)
+
+ warnings.warn(
+ "Argument '%s' is now named '%s' for function '%s'" %
+ (oldname, newname, fn.__name__))
+ if not has_keywords and names:
+ raise TypeError("Unknown arguments: %s" % ", ".join(names))
+ return fn(*arg, **kw)
+
+ code = 'lambda %(args)s: %(target)s(%(apply_kw)s)' % (
+ metadata)
+ decorated = eval(code, {"target": go})
+ decorated.func_defaults = getattr(fn, 'im_func', fn).func_defaults
+ return update_wrapper(decorated, fn)
+
+ return decorate
+
+
+
==========
.. changelog::
- :version: 0.4.3
+ :version: 0.5.0
.. change::
- :tags: bug, documentation
+ :tags: bug
+ :tickets: 104
+
+ A host of argument name changes within migration
+ operations for consistency. Keyword arguments
+ will continue to work on the old name for backwards compatibility,
+ however required positional arguments will not:
+
+ :meth:`.Operations.alter_column` - ``name`` -> ``new_column_name`` - old
+ name will work for backwards compatibility.
+
+ :meth:`.Operations.create_index` - ``tablename`` -> ``table_name`` -
+ argument is positional.
+
+ :meth:`.Operations.drop_index` - ``tablename`` -> ``table_name`` - old
+ name will work for backwards compatibility.
+
+ :meth:`.Operations.drop_constraint` - ``tablename`` -> ``table_name`` -
+ argument is positional.
- The name of the "type" parameter on :func:`.drop_constraint`
- is now officially named ``type_`` for consistency.
- ``type`` will remain in at least the near future for
- backwards compatibility.
+ :meth:`.Operations.drop_constraint` - ``type`` -> ``type_`` - old
+ name will work for backwards compatibility
.. changelog::
:version: 0.4.2
def test_alter_column_rename_mssql(self):
context = op_fixture('mssql')
- op.alter_column("t", "c", name="x")
+ op.alter_column("t", "c", new_column_name="x")
context.assert_(
"EXEC sp_rename 't.c', 'x', 'COLUMN'"
)
def test_alter_do_everything(self):
context = op_fixture('mssql')
- op.alter_column("t", "c", name="c2", nullable=True, type_=Integer, server_default="5")
+ op.alter_column("t", "c", new_column_name="c2", nullable=True,
+ type_=Integer, server_default="5")
context.assert_(
'ALTER TABLE t ALTER COLUMN c INTEGER NULL',
"ALTER TABLE t ADD DEFAULT '5' FOR c",
from sqlalchemy import Integer, Column, ForeignKey, \
UniqueConstraint, Table, MetaData, String,\
func
-from sqlalchemy.sql import table
def test_rename_column():
context = op_fixture('mysql')
- op.alter_column('t1', 'c1', name="c2", existing_type=Integer)
+ op.alter_column('t1', 'c1', new_column_name="c2", existing_type=Integer)
context.assert_(
'ALTER TABLE t1 CHANGE c1 c2 INTEGER NULL'
)
def test_rename_column_serv_default():
context = op_fixture('mysql')
- op.alter_column('t1', 'c1', name="c2", existing_type=Integer, existing_server_default="q")
+ op.alter_column('t1', 'c1', new_column_name="c2", existing_type=Integer,
+ existing_server_default="q")
context.assert_(
"ALTER TABLE t1 CHANGE c1 c2 INTEGER NULL DEFAULT 'q'"
)
def test_rename_column_serv_compiled_default():
context = op_fixture('mysql')
- op.alter_column('t1', 'c1', name="c2", existing_type=Integer,
+ op.alter_column('t1', 'c1', new_column_name="c2", existing_type=Integer,
existing_server_default=func.utc_thing(func.current_timestamp()))
# this is not a valid MySQL default but the point is to just
# test SQL expression rendering
def test_rename_column_autoincrement():
context = op_fixture('mysql')
- op.alter_column('t1', 'c1', name="c2", existing_type=Integer,
+ op.alter_column('t1', 'c1', new_column_name="c2", existing_type=Integer,
existing_autoincrement=True)
context.assert_(
'ALTER TABLE t1 CHANGE c1 c2 INTEGER NULL AUTO_INCREMENT'
def test_col_add_autoincrement():
context = op_fixture('mysql')
- op.alter_column('t1', 'c1', name="c2", existing_type=Integer,
+ op.alter_column('t1', 'c1', new_column_name="c2", existing_type=Integer,
autoincrement=True)
context.assert_(
'ALTER TABLE t1 CHANGE c1 c2 INTEGER NULL AUTO_INCREMENT'
def test_col_remove_autoincrement():
context = op_fixture('mysql')
- op.alter_column('t1', 'c1', name="c2", existing_type=Integer,
+ op.alter_column('t1', 'c1', new_column_name="c2", existing_type=Integer,
existing_autoincrement=True,
autoincrement=False)
context.assert_(
def test_drop_constraint_primary():
context = op_fixture('mysql')
- op.drop_constraint('primary', 't1',type='primary')
+ op.drop_constraint('primary', 't1', type_='primary')
context.assert_(
"ALTER TABLE t1 DROP PRIMARY KEY "
)
from tests import op_fixture, assert_raises_message
from alembic import op
from sqlalchemy import Integer, Column, ForeignKey, \
- UniqueConstraint, Table, MetaData, String,\
- Boolean
-from sqlalchemy.sql import table, column, func
+ Table, String, Boolean
+from sqlalchemy.sql import column, func
def test_rename_table():
def test_alter_column_rename():
context = op_fixture()
- op.alter_column("t", "c", name="x")
+ op.alter_column("t", "c", new_column_name="x")
context.assert_(
"ALTER TABLE t RENAME c TO x"
)
def test_alter_column_schema_rename():
context = op_fixture()
- op.alter_column("t", "c", name="x", schema='foo')
+ op.alter_column("t", "c", new_column_name="x", schema='foo')
context.assert_(
"ALTER TABLE foo.t RENAME c TO x"
)
)
op.execute(
account.update().\
- where(account.c.name==op.inline_literal('account 1')).\
- values({'name':op.inline_literal('account 2')})
+ where(account.c.name == op.inline_literal('account 1')).\
+ values({'name': op.inline_literal('account 2')})
)
op.execute(
account.update().\
- where(account.c.id==op.inline_literal(1)).\
- values({'id':op.inline_literal(2)})
+ where(account.c.id == op.inline_literal(1)).\
+ values({'id': op.inline_literal(2)})
)
context.assert_(
"UPDATE account SET name='account 2' WHERE account.name = 'account 1'",
"Try placing this code inside a callable.",
op.inline_literal, "asdf"
)
+
+
+def test_naming_changes():
+ context = op_fixture()
+ op.alter_column("t", "c", name="x")
+ context.assert_("ALTER TABLE t RENAME c TO x")
+
+ context = op_fixture()
+ op.alter_column("t", "c", new_column_name="x")
+ context.assert_("ALTER TABLE t RENAME c TO x")
+
+ context = op_fixture('mssql')
+ op.drop_index('ik_test', tablename='t1')
+ context.assert_("DROP INDEX [t1].ik_test")
+
+ context = op_fixture('mssql')
+ op.drop_index('ik_test', table_name='t1')
+ context.assert_("DROP INDEX [t1].ik_test")
+
+ context = op_fixture('mysql')
+ op.drop_constraint("f1", "t1", type="foreignkey")
+ context.assert_("ALTER TABLE t1 DROP FOREIGN KEY f1")
+
+ context = op_fixture('mysql')
+ op.drop_constraint("f1", "t1", type_="foreignkey")
+ context.assert_("ALTER TABLE t1 DROP FOREIGN KEY f1")
+
+ assert_raises_message(
+ TypeError,
+ "Unknown arguments: badarg2, badarg1",
+ op.alter_column, "t", "c", badarg1="x", badarg2="y"
+ )
+