summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--alembic/autogenerate/render.py13
-rw-r--r--alembic/testing/requirements.py7
-rw-r--r--alembic/util/__init__.py1
-rw-r--r--alembic/util/sqla_compat.py8
-rw-r--r--docs/build/unreleased/518.rst8
-rw-r--r--tests/test_autogen_render.py33
-rw-r--r--tests/test_sqlite.py11
7 files changed, 79 insertions, 2 deletions
diff --git a/alembic/autogenerate/render.py b/alembic/autogenerate/render.py
index 24eeb4e..f09f5ae 100644
--- a/alembic/autogenerate/render.py
+++ b/alembic/autogenerate/render.py
@@ -616,11 +616,20 @@ def _render_column(column, autogen_context):
opts.append(("comment", "%r" % comment))
# TODO: for non-ascii colname, assign a "key"
- return "%(prefix)sColumn(%(name)r, %(type)s, %(kw)s)" % {
+ return "%(prefix)sColumn(%(name)r, %(type)s, %(kwargs)s)" % {
"prefix": _sqlalchemy_autogenerate_prefix(autogen_context),
"name": _ident(column.name),
"type": _repr_type(column.type, autogen_context),
- "kw": ", ".join(["%s=%s" % (kwname, val) for kwname, val in opts]),
+ "kwargs": (
+ ", ".join(
+ ["%s=%s" % (kwname, val) for kwname, val in opts]
+ + [
+ "%s=%s"
+ % (key, _render_potential_expr(val, autogen_context))
+ for key, val in sqla_compat._column_kwargs(column).items()
+ ]
+ )
+ ),
}
diff --git a/alembic/testing/requirements.py b/alembic/testing/requirements.py
index 9038a45..cd9daa6 100644
--- a/alembic/testing/requirements.py
+++ b/alembic/testing/requirements.py
@@ -78,6 +78,13 @@ class SuiteRequirements(Requirements):
)
@property
+ def sqlalchemy_13(self):
+ return exclusions.skip_if(
+ lambda config: not util.sqla_13,
+ "SQLAlchemy 1.3 or greater required",
+ )
+
+ @property
def sqlalchemy_1115(self):
return exclusions.skip_if(
lambda config: not util.sqla_1115,
diff --git a/alembic/util/__init__.py b/alembic/util/__init__.py
index 5a765fe..fbe88e3 100644
--- a/alembic/util/__init__.py
+++ b/alembic/util/__init__.py
@@ -25,6 +25,7 @@ from .sqla_compat import sqla_110 # noqa
from .sqla_compat import sqla_1115 # noqa
from .sqla_compat import sqla_120 # noqa
from .sqla_compat import sqla_1216 # noqa
+from .sqla_compat import sqla_13 # noqa
if not sqla_110:
diff --git a/alembic/util/sqla_compat.py b/alembic/util/sqla_compat.py
index 46becc0..3733142 100644
--- a/alembic/util/sqla_compat.py
+++ b/alembic/util/sqla_compat.py
@@ -29,6 +29,7 @@ sqla_110 = _vers >= (1, 1, 0)
sqla_1115 = _vers >= (1, 1, 15)
sqla_120 = _vers >= (1, 2, 0)
sqla_1216 = _vers >= (1, 2, 16)
+sqla_13 = _vers >= (1, 3)
sqla_14 = _vers >= (1, 4)
@@ -174,6 +175,13 @@ def _get_index_column_names(idx):
return [getattr(exp, "name", None) for exp in _get_index_expressions(idx)]
+def _column_kwargs(col):
+ if sqla_13:
+ return col.kwargs
+ else:
+ return {}
+
+
def _get_index_final_name(dialect, idx):
# trying to keep the truncation rules totally localized on the
# SQLA side while also stepping around the quoting issue. Ideally
diff --git a/docs/build/unreleased/518.rst b/docs/build/unreleased/518.rst
new file mode 100644
index 0000000..46094d3
--- /dev/null
+++ b/docs/build/unreleased/518.rst
@@ -0,0 +1,8 @@
+.. change::
+ :tags: usecase, autogenerate
+ :tickets: 518
+
+ Added autogenerate support for :class:`.Column` objects that have
+ dialect-specific ``**kwargs``, support first added in SQLAlchemy 1.3.
+ This includes SQLite "on conflict" as well as options used by some
+ third party dialects.
diff --git a/tests/test_autogen_render.py b/tests/test_autogen_render.py
index ef2130a..14a8684 100644
--- a/tests/test_autogen_render.py
+++ b/tests/test_autogen_render.py
@@ -22,6 +22,7 @@ from sqlalchemy import Numeric
from sqlalchemy import PrimaryKeyConstraint
from sqlalchemy import String
from sqlalchemy import Table
+from sqlalchemy import testing
from sqlalchemy import text
from sqlalchemy import types
from sqlalchemy import Unicode
@@ -89,6 +90,23 @@ class AutogenRenderTest(TestBase):
"['active', 'code'], unique=False)",
)
+ @testing.emits_warning("Can't validate argument ")
+ def test_render_add_index_custom_kwarg(self):
+ t = Table(
+ "test",
+ MetaData(),
+ Column("id", Integer, primary_key=True),
+ Column("active", Boolean()),
+ Column("code", String(255)),
+ )
+ idx = Index(None, t.c.active, t.c.code, somedialect_foobar="option")
+ op_obj = ops.CreateIndexOp.from_index(idx)
+ eq_ignore_whitespace(
+ autogenerate.render_op_text(self.autogen_context, op_obj),
+ "op.create_index(op.f('ix_test_active'), 'test', "
+ "['active', 'code'], unique=False, somedialect_foobar='option')",
+ )
+
def test_render_add_index_batch(self):
"""
autogenerate.render._add_index
@@ -1057,6 +1075,21 @@ class AutogenRenderTest(TestBase):
"server_default='5', nullable=True))",
)
+ @testing.requires.sqlalchemy_13
+ @testing.emits_warning("Can't validate argument ")
+ def test_render_add_column_custom_kwarg(self):
+ col = Column(
+ "x", Integer, server_default="5", somedialect_foobar="option"
+ )
+ Table("foo", MetaData(), col)
+
+ op_obj = ops.AddColumnOp.from_column(col)
+ eq_ignore_whitespace(
+ autogenerate.render_op_text(self.autogen_context, op_obj),
+ "op.add_column('foo', sa.Column('x', sa.Integer(), "
+ "server_default='5', nullable=True, somedialect_foobar='option'))",
+ )
+
def test_render_add_column_system(self):
# this would never actually happen since "system" columns
# can't be added in any case. Howver it will render as
diff --git a/tests/test_sqlite.py b/tests/test_sqlite.py
index 7616ef2..2c416bc 100644
--- a/tests/test_sqlite.py
+++ b/tests/test_sqlite.py
@@ -256,3 +256,14 @@ class SQLiteAutogenRenderTest(TestBase):
"sa.Column('int_value', sa.Integer(), server_default='5', "
"nullable=True)",
)
+
+ @config.requirements.sqlalchemy_13
+ def test_render_add_column_w_on_conflict(self):
+ c = Column("int_value", Integer, sqlite_on_conflict_not_null="FAIL")
+
+ result = autogenerate.render._render_column(c, self.autogen_context)
+ eq_ignore_whitespace(
+ result,
+ "sa.Column('int_value', sa.Integer(), "
+ "nullable=True, sqlite_on_conflict_not_null='FAIL')",
+ )