diff options
-rw-r--r-- | alembic/autogenerate/render.py | 13 | ||||
-rw-r--r-- | alembic/testing/requirements.py | 7 | ||||
-rw-r--r-- | alembic/util/__init__.py | 1 | ||||
-rw-r--r-- | alembic/util/sqla_compat.py | 8 | ||||
-rw-r--r-- | docs/build/unreleased/518.rst | 8 | ||||
-rw-r--r-- | tests/test_autogen_render.py | 33 | ||||
-rw-r--r-- | tests/test_sqlite.py | 11 |
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')", + ) |