summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2015-06-24 16:48:04 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2015-06-24 16:54:27 -0400
commit69588e424a8e0fa2b367851219f2ed1f634e8ba2 (patch)
tree1758b7ccd18214befae5d0d33250e1eb1efc072f
parent9eaa306423a8876783dc25699530dd2d8d889866 (diff)
downloadalembic-69588e424a8e0fa2b367851219f2ed1f634e8ba2.tar.gz
- continue to scale back how much magic we're building into this
for now
-rw-r--r--alembic/ddl/base.py1
-rw-r--r--alembic/ddl/mssql.py6
-rw-r--r--alembic/ddl/mysql.py7
-rw-r--r--alembic/operations/__init__.py9
-rw-r--r--alembic/operations/base.py61
-rw-r--r--alembic/operations/ops.py78
-rw-r--r--alembic/operations/schemaobj.py2
-rw-r--r--alembic/operations/toimpl.py104
-rw-r--r--alembic/util/__init__.py2
-rw-r--r--alembic/util/langhelpers.py33
-rw-r--r--tests/test_op.py6
11 files changed, 137 insertions, 172 deletions
diff --git a/alembic/ddl/base.py b/alembic/ddl/base.py
index ed0c6f8..f4a525f 100644
--- a/alembic/ddl/base.py
+++ b/alembic/ddl/base.py
@@ -3,6 +3,7 @@ import functools
from sqlalchemy.ext.compiler import compiles
from sqlalchemy.schema import DDLElement, Column
from sqlalchemy import Integer
+from sqlalchemy import types as sqltypes
from .. import util
# backwards compat
diff --git a/alembic/ddl/mssql.py b/alembic/ddl/mssql.py
index f516e9b..f51de33 100644
--- a/alembic/ddl/mssql.py
+++ b/alembic/ddl/mssql.py
@@ -39,11 +39,10 @@ class MSSQLImpl(DefaultImpl):
name=None,
type_=None,
schema=None,
- autoincrement=None,
existing_type=None,
existing_server_default=None,
existing_nullable=None,
- existing_autoincrement=None
+ **kw
):
if nullable is not None and existing_type is None:
@@ -63,10 +62,9 @@ class MSSQLImpl(DefaultImpl):
nullable=nullable,
type_=type_,
schema=schema,
- autoincrement=autoincrement,
existing_type=existing_type,
existing_nullable=existing_nullable,
- existing_autoincrement=existing_autoincrement
+ **kw
)
if server_default is not False:
diff --git a/alembic/ddl/mysql.py b/alembic/ddl/mysql.py
index fe42145..b1cb324 100644
--- a/alembic/ddl/mysql.py
+++ b/alembic/ddl/mysql.py
@@ -23,11 +23,12 @@ class MySQLImpl(DefaultImpl):
name=None,
type_=None,
schema=None,
- autoincrement=None,
existing_type=None,
existing_server_default=None,
existing_nullable=None,
- existing_autoincrement=None
+ autoincrement=None,
+ existing_autoincrement=None,
+ **kw
):
if name is not None:
self._exec(
@@ -284,3 +285,5 @@ def _mysql_drop_constraint(element, compiler, **kw):
raise NotImplementedError(
"No generic 'DROP CONSTRAINT' in MySQL - "
"please specify constraint type")
+
+
diff --git a/alembic/operations/__init__.py b/alembic/operations/__init__.py
index 945169c..f01860d 100644
--- a/alembic/operations/__init__.py
+++ b/alembic/operations/__init__.py
@@ -1,11 +1,2 @@
from .base import Operations, BatchOperations
-from .ops import (
- RenameTable, AddColumn, DropColumn, AlterColumn,
- ColumnNullable, ColumnDefault, ColumnType, ColumnName)
-
-
-__all__ = (
- 'Operations', 'BatchOperations', 'RenameTable',
- 'AddColumn', 'DropColumn', 'AlterColumn',
- 'ColumnNullable', 'ColumnDefault', 'ColumnType', 'ColumnName')
diff --git a/alembic/operations/base.py b/alembic/operations/base.py
index 250d1fe..5162101 100644
--- a/alembic/operations/base.py
+++ b/alembic/operations/base.py
@@ -7,6 +7,8 @@ from .. import util
from ..util import sqla_compat
from . import batch
from . import schemaobj
+from . import ops
+from . import toimpl
__all__ = ('Operations', 'BatchOperations')
@@ -234,18 +236,17 @@ class Operations(object):
)
@util._with_legacy_names([('name', 'new_column_name')])
- def alter_column(self, table_name, column_name,
- nullable=None,
- server_default=False,
- new_column_name=None,
- type_=None,
- autoincrement=None,
- existing_type=None,
- existing_server_default=False,
- existing_nullable=None,
- existing_autoincrement=None,
- schema=None
- ):
+ def alter_column(
+ self, table_name, column_name,
+ nullable=None,
+ server_default=False,
+ new_column_name=None,
+ type_=None,
+ existing_type=None,
+ existing_server_default=False,
+ existing_nullable=None,
+ schema=None, **kw
+ ):
"""Issue an "alter column" instruction using the
current migration context.
@@ -321,26 +322,30 @@ class Operations(object):
:class:`~sqlalchemy.sql.elements.quoted_name` construct.
"""
- if autoincrement is not None:
- # TODO: or we add **kw to AlterColumnOp
- cls = mysql.MySQLAlterColumnOp
- else:
- cls = ops.AlterColumnOp
-
- op = cls.from_alter_column(
- table_name, column_name,
- nullable=nullable,
- server_default=server_default,
- new_column_name=new_column_name,
- type_=type_,
+
+ alt = ops.AlterColumnOp(
+ table_name, column_name, schema=schema,
existing_type=existing_type,
existing_server_default=existing_server_default,
- existing_nullable=existing_nullable,
- schema=schema
+ existing_nullable=existing_nullable
)
- # hits a ToImpl object
- self.invoke(op)
+ alt.kw = kw
+ if new_column_name is not None:
+ alt.modify_name = new_column_name
+ if type_ is not None:
+ alt.modify_type = type_
+ if server_default is not False:
+ alt.modify_server_default = server_default
+ if nullable is not None:
+ alt.modify_nullable = nullable
+
+ return self.invoke(alt)
+
+ def invoke(self, operation):
+ fn = ops.to_impl.dispatch(
+ operation, self.migration_context.impl.__dialect__)
+ return fn(self, operation)
def f(self, name):
"""Indicate a string name that has already had a naming convention
diff --git a/alembic/operations/ops.py b/alembic/operations/ops.py
index 4cc3258..e34ff09 100644
--- a/alembic/operations/ops.py
+++ b/alembic/operations/ops.py
@@ -1,3 +1,8 @@
+from .. import util
+
+
+to_impl = util.Dispatcher()
+
class MigrateOperation(object):
"""base class for migration command and organization objects."""
@@ -131,74 +136,27 @@ class RenameTableOp(AlterTableOp):
class AlterColumnOp(AlterTableOp):
- def __init__(self, table_name, column_name, schema=None):
+ def __init__(
+ self, table_name, column_name, schema=None,
+ existing_type=None,
+ existing_server_default=False,
+ existing_nullable=None
+ ):
super(AlterColumnOp, self).__init__(table_name, schema=schema)
self.column_name = column_name
+ self.existing_type = existing_type
+ self.existing_server_default = existing_server_default
+ self.existing_nullable = existing_nullable
modify_nullable = None
modify_server_default = False
modify_name = None
modify_type = None
+ kw = None
def dispatch_for(self, handler):
return handler.alter_column
- @classmethod
- def from_alter_column(
- cls, table_name, column_name,
- nullable=None,
- server_default=False,
- name=None,
- type_=None,
- schema=None,
- existing_type=None,
- existing_server_default=None,
- existing_nullable=None):
- """Generate an AlterColumn object from a set of 'alter_column'
- arguments.
-
- The 'alter_column' arguments are common throughout Alembic, both
- because this is the legacy API for altering columns as well as that
- it remains the primary public API from the Operations object.
- Internally, we seek to be able to convert between these arguments
- and distinct AlterColumnElement operations grouped together.
-
- """
-
- alt = AlterColumnOp(
- table_name, column_name, schema=schema,
- existing_type=existing_type,
- existing_server_default=existing_server_default,
- existing_nullable=existing_nullable
- )
-
- if name is not None:
- alt.modify_name = name
- if type_ is not None:
- alt.modify_type = type_,
- if server_default is not False:
- alt.modify_server_default = server_default
- if nullable is not None:
- alt.modify_nullable = nullable
-
- return alt
-
- @property
- def has_nullable(self):
- return self.modify_nullable is not None
-
- @property
- def has_type(self):
- return self.modify_type is not None
-
- @property
- def has_server_default(self):
- return self.modify_server_default is not False
-
- @property
- def has_name(self):
- return self.modify_name is not None
-
class AddColumnOp(AlterTableOp):
@@ -259,9 +217,3 @@ class MigrationScript(OpContainer):
"""
-
-class MigrationDispatch(object):
- def handle(self, operation, **kw):
- fn = operation.dispatch_for(self)
- return fn(operation, **kw)
-
diff --git a/alembic/operations/schemaobj.py b/alembic/operations/schemaobj.py
index 575226a..4e0474e 100644
--- a/alembic/operations/schemaobj.py
+++ b/alembic/operations/schemaobj.py
@@ -106,7 +106,7 @@ class SchemaObjects(object):
)
idx = sa_schema.Index(
name,
- *[util._textual_index_column(t, n) for n in columns],
+ *[util.sqla_compat._textual_index_column(t, n) for n in columns],
**kw)
return idx
diff --git a/alembic/operations/toimpl.py b/alembic/operations/toimpl.py
index b1a5348..b3688ff 100644
--- a/alembic/operations/toimpl.py
+++ b/alembic/operations/toimpl.py
@@ -1,50 +1,62 @@
-from .ops import MigrationDispatch
+from . import ops
+from sqlalchemy import schema as sa_schema
-class ToImpl(MigrationDispatch):
- """translates from ops objects into commands sent to DefaultImpl."""
- def alter_column(self, operation):
- compiler = self.impl.dialect.statement_compiler(
- self.impl.dialect,
- None
+@ops.to_impl.dispatch_for(ops.AlterColumnOp, 'default')
+def alter_column(operations, operation):
+
+ compiler = operations.impl.dialect.statement_compiler(
+ operations.impl.dialect,
+ None
+ )
+
+ existing_type = operation.existing_type
+ existing_nullable = operation.existing_nullable
+ existing_server_default = operation.existing_server_default
+ type_ = operation.modify_type
+ column_name = operation.column_name
+ table_name = operation.table_name
+ schema = operation.schema
+ server_default = operation.modify_server_default
+ new_column_name = operation.modify_name
+ nullable = operation.modify_nullable
+
+ def _count_constraint(constraint):
+ return not isinstance(
+ constraint,
+ sa_schema.PrimaryKeyConstraint) and \
+ (not constraint._create_rule or
+ constraint._create_rule(compiler))
+
+ if existing_type and type_:
+ t = operations.schema_obj.table(
+ table_name,
+ sa_schema.Column(column_name, existing_type),
+ schema=schema
)
+ for constraint in t.constraints:
+ if _count_constraint(constraint):
+ operations.impl.drop_constraint(constraint)
+
+ operations.impl.alter_column(
+ table_name, column_name,
+ nullable=nullable,
+ server_default=server_default,
+ name=new_column_name,
+ type_=type_,
+ schema=schema,
+ existing_type=existing_type,
+ existing_server_default=existing_server_default,
+ existing_nullable=existing_nullable,
+ **operation.kw
+ )
- def _count_constraint(constraint):
- return not isinstance(
- constraint,
- sa_schema.PrimaryKeyConstraint) and \
- (not constraint._create_rule or
- constraint._create_rule(compiler))
-
- if existing_type and type_:
- t = self.schema_obj.table(
- table_name,
- sa_schema.Column(column_name, existing_type),
- schema=schema
- )
- for constraint in t.constraints:
- if _count_constraint(constraint):
- self.impl.drop_constraint(constraint)
-
- self.impl.alter_column(table_name, column_name,
- nullable=nullable,
- server_default=server_default,
- name=new_column_name,
- type_=type_,
- schema=schema,
- autoincrement=autoincrement,
- existing_type=existing_type,
- existing_server_default=existing_server_default,
- existing_nullable=existing_nullable,
- existing_autoincrement=existing_autoincrement
- )
-
- if type_:
- t = self.schema_obj.table(
- table_name,
- self.schema_obj.column(column_name, type_),
- schema=schema
- )
- for constraint in t.constraints:
- if _count_constraint(constraint):
- self.impl.add_constraint(constraint)
+ if type_:
+ t = operations.schema_obj.table(
+ table_name,
+ operations.schema_obj.column(column_name, type_),
+ schema=schema
+ )
+ for constraint in t.constraints:
+ if _count_constraint(constraint):
+ operations.impl.add_constraint(constraint)
diff --git a/alembic/util/__init__.py b/alembic/util/__init__.py
index 6cfc5d3..0fb3b1d 100644
--- a/alembic/util/__init__.py
+++ b/alembic/util/__init__.py
@@ -1,6 +1,6 @@
from .langhelpers import ( # noqa
create_module_class_proxy, asbool, rev_id, to_tuple, memoized_property,
- immutabledict, _with_legacy_names)
+ immutabledict, _with_legacy_names, Dispatcher)
from .messaging import ( # noqa
write_outstream, status, err, obfuscate_url_pw, warn, msg, format_as_comma)
from .pyfiles import ( # noqa
diff --git a/alembic/util/langhelpers.py b/alembic/util/langhelpers.py
index 5886125..8e2fb90 100644
--- a/alembic/util/langhelpers.py
+++ b/alembic/util/langhelpers.py
@@ -33,8 +33,16 @@ def create_module_class_proxy(cls, globals_, locals_):
for name in attr_names:
del globals_[name]
+ def _add_proxied_method(methname):
+ if not methname.startswith('_'):
+ if callable(getattr(cls, methname)):
+ locals_[methname] = _create_op_proxy(methname)
+ else:
+ attr_names.add(methname)
+
globals_['_install_proxy'] = _install_proxy
globals_['_remove_proxy'] = _remove_proxy
+ globals_['_add_proxied_method'] = _add_proxied_method
def _create_op_proxy(name):
fn = getattr(cls, name)
@@ -86,11 +94,7 @@ def create_module_class_proxy(cls, globals_, locals_):
return lcl[name]
for methname in dir(cls):
- if not methname.startswith('_'):
- if callable(getattr(cls, methname)):
- locals_[methname] = _create_op_proxy(methname)
- else:
- attr_names.add(methname)
+ _add_proxied_method(methname)
def asbool(value):
@@ -210,14 +214,19 @@ class Dispatcher(object):
def __init__(self):
self._registry = {}
- def dispatch_for(self, fn, target):
- assert isinstance(target, type)
- assert target not in self._registry
- self._registry[target] = fn
+ def dispatch_for(self, target, qualifier='default'):
+ def decorate(fn):
+ assert isinstance(target, type)
+ assert target not in self._registry
+ self._registry[(target, qualifier)] = fn
+ return fn
+ return decorate
- def dispatch(self, obj):
+ def dispatch(self, obj, qualifier='default'):
for spcls in type(obj).__mro__:
- if spcls in self._registry:
- return self._registry[spcls]
+ if qualifier != 'default' and (spcls, qualifier) in self._registry:
+ return self._registry[(spcls, qualifier)]
+ elif (spcls, 'default') in self._registry:
+ return self._registry[(spcls, 'default')]
else:
raise ValueError("no dispatch function for object: %s" % obj)
diff --git a/tests/test_op.py b/tests/test_op.py
index 5be9aa8..7b61697 100644
--- a/tests/test_op.py
+++ b/tests/test_op.py
@@ -809,12 +809,6 @@ class OpTest(TestBase):
op.drop_constraint("f1", "t1", type_="foreignkey")
context.assert_("ALTER TABLE t1 DROP FOREIGN KEY f1")
- assert_raises_message(
- TypeError,
- r"Unknown arguments: badarg\d, badarg\d",
- op.alter_column, "t", "c", badarg1="x", badarg2="y"
- )
-
@config.requirements.fail_before_sqla_084
def test_naming_changes_drop_idx(self):
context = op_fixture('mssql')