From: Mike Bayer Date: Mon, 11 Feb 2013 19:37:59 +0000 (-0500) Subject: - move to 0.5.0 as we are making some slight naming changes X-Git-Tag: rel_0_5_0~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8cdd16e401c022a0163016f686f2d9c772fd8fdc;p=thirdparty%2Fsqlalchemy%2Falembic.git - move to 0.5.0 as we are making some slight naming changes - add a generalized approach for renamed kw args, accepting the old ones using a specialized decorator - change "tablename" to "table_name" for create_index, drop_index, drop_constraint - change "name" to "new_column_name" for alter_column #104 --- diff --git a/alembic/__init__.py b/alembic/__init__.py index 2ca08edb..eb810282 100644 --- a/alembic/__init__.py +++ b/alembic/__init__.py @@ -1,6 +1,6 @@ from os import path -__version__ = '0.4.3' +__version__ = '0.5.0' package_dir = path.abspath(path.dirname(__file__)) diff --git a/alembic/operations.py b/alembic/operations.py index 4dff7baf..f5640c5b 100644 --- a/alembic/operations.py +++ b/alembic/operations.py @@ -1,7 +1,7 @@ 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 @@ -162,10 +162,11 @@ class Operations(object): 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, @@ -210,8 +211,14 @@ class Operations(object): 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. @@ -267,7 +274,7 @@ class Operations(object): 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, @@ -592,7 +599,7 @@ class Operations(object): 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. @@ -602,7 +609,13 @@ class Operations(object): 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. @@ -612,21 +625,27 @@ class Operations(object): """ 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 @@ -635,43 +654,45 @@ class Operations(object): # 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_] diff --git a/alembic/util.py b/alembic/util.py index bf2c89d1..6d7caf08 100644 --- a/alembic/util.py +++ b/alembic/util.py @@ -5,14 +5,12 @@ import sys 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 @@ -251,3 +249,44 @@ class immutabledict(dict): 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 + + + diff --git a/docs/build/changelog.rst b/docs/build/changelog.rst index 9f8dd249..8e52544f 100644 --- a/docs/build/changelog.rst +++ b/docs/build/changelog.rst @@ -4,15 +4,31 @@ Changelog ========== .. 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 diff --git a/tests/test_mssql.py b/tests/test_mssql.py index 280003ca..4113e333 100644 --- a/tests/test_mssql.py +++ b/tests/test_mssql.py @@ -53,7 +53,7 @@ class OpTest(TestCase): 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'" ) @@ -154,7 +154,8 @@ class OpTest(TestCase): 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", diff --git a/tests/test_mysql.py b/tests/test_mysql.py index 456aab7c..50483766 100644 --- a/tests/test_mysql.py +++ b/tests/test_mysql.py @@ -3,25 +3,25 @@ from alembic import op, util 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 @@ -31,7 +31,7 @@ def test_rename_column_serv_compiled_default(): 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' @@ -39,7 +39,7 @@ def test_rename_column_autoincrement(): 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' @@ -47,7 +47,7 @@ def test_col_add_autoincrement(): 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_( @@ -86,7 +86,7 @@ def test_drop_fk(): 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 " ) diff --git a/tests/test_op.py b/tests/test_op.py index 6feb7eec..438a5476 100644 --- a/tests/test_op.py +++ b/tests/test_op.py @@ -3,9 +3,8 @@ 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(): @@ -169,14 +168,14 @@ def test_alter_column_schema_not_nullable(): 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" ) @@ -550,13 +549,13 @@ def test_inline_literal(): ) 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'", @@ -574,3 +573,36 @@ def test_cant_op(): "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" + ) +