]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Support autogenerate for add_column kwargs
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 17 Sep 2019 23:00:50 +0000 (19:00 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 18 Sep 2019 00:59:42 +0000 (20:59 -0400)
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.

Change-Id: Iede4ee74e74181f2f2357c6a69c6f3fa0c985392
Fixes: #518
alembic/autogenerate/render.py
alembic/testing/requirements.py
alembic/util/__init__.py
alembic/util/sqla_compat.py
docs/build/unreleased/518.rst [new file with mode: 0644]
tests/test_autogen_render.py
tests/test_sqlite.py

index 24eeb4e7ac431040d58d4cf4d1bf7340bdb476b6..f09f5ae08447088db88e210ba223b28a4f06883f 100644 (file)
@@ -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()
+                ]
+            )
+        ),
     }
 
 
index 9038a45c65ebc609d65c77f19aa64445a0d95f33..cd9daa6eaf999af66630fb8908b4d772e6cb13ff 100644 (file)
@@ -77,6 +77,13 @@ class SuiteRequirements(Requirements):
             "SQLAlchemy 1.2.16 or greater required",
         )
 
+    @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(
index 5a765fee89fd9b4a954fdb3ef69ac0a7757c7d3f..fbe88e3a8b5d239c1e306ca8cbd08f03d10a7634 100644 (file)
@@ -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:
index 46becc0596cd8289435ed36919de5832dfd50c01..373314256bd7b82a539f0320e74a75a5bdebecd2 100644 (file)
@@ -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 (file)
index 0000000..46094d3
--- /dev/null
@@ -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.
index ef2130a3651281a9011b30497f9187d72f6ea764..14a86841d0d7985f1ef6e8b3c140237b4a4f82cd 100644 (file)
@@ -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
index 7616ef20c77c5782253b7a005c1ad4542d92717d..2c416bcb3f0808ae79736602a23e46eaf52d2cef 100644 (file)
@@ -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')",
+        )