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()
+ ]
+ )
+ ),
}
"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(
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:
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)
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
--- /dev/null
+.. 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.
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
"['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
"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
"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')",
+ )