]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Fix rendering of Column objects in dialect kwargs like postgresql_inc…
authorAjaysingh-2003 <linkajay2003@gmail.com>
Wed, 8 Apr 2026 13:45:05 +0000 (09:45 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Apr 2026 14:10:21 +0000 (10:10 -0400)
Fixed rendering of dialect keyword arguments containing
:class:`~sqlalchemy.schema.Column` objects within sequences, such as
``postgresql_include``.  These were previously rendered using ``repr()``,
producing invalid Python in the generated migration scripts.  Column
objects within list or tuple values are now correctly rendered as their
string column names.  Pull request courtesy Ajay Singh.

Fixes: #1258
Closes: #1802
Pull-request: https://github.com/sqlalchemy/alembic/pull/1802
Pull-request-sha: 2a0441c3b21602ea6bd83aca0877f562c2c64c25

Change-Id: Idc8f1d785899ec1b2b972d6e50813afe136e47a0

alembic/autogenerate/render.py
docs/build/unreleased/1258.rst [new file with mode: 0644]
tests/test_autogen_render.py

index 7f32838df7b292a86c1fd60d23a2926046653020..4cae1cf31edcef8b5dc516f1be257d7070e0ec95 100644 (file)
@@ -618,7 +618,22 @@ def _render_potential_expr(
     is_server_default: bool = False,
     is_index: bool = False,
 ) -> str:
-    if isinstance(value, sql.ClauseElement):
+
+    if isinstance(value, (list, tuple)):
+        rendered = [
+            _render_potential_expr(item, autogen_context) for item in value
+        ]
+        if isinstance(value, tuple):
+            return "(%s%s)" % (
+                ", ".join(rendered),
+                "," if len(rendered) == 1 else "",
+            )
+        else:
+            return "[%s]" % ", ".join(rendered)
+
+    elif isinstance(value, sa_schema.Column):
+        return repr(_ident(getattr(value, "name", None)))
+    elif isinstance(value, sql.ClauseElement):
         sql_text = autogen_context.migration_context.impl.render_ddl_sql_expr(
             value, is_server_default=is_server_default, is_index=is_index
         )
diff --git a/docs/build/unreleased/1258.rst b/docs/build/unreleased/1258.rst
new file mode 100644 (file)
index 0000000..ad73a65
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+    :tags: bug, autogenerate
+    :tickets: 1258
+
+    Fixed rendering of dialect keyword arguments containing
+    :class:`~sqlalchemy.schema.Column` objects within sequences, such as
+    ``postgresql_include``.  These were previously rendered using ``repr()``,
+    producing invalid Python in the generated migration scripts.  Column
+    objects within list or tuple values are now correctly rendered as their
+    string column names.  Pull request courtesy Ajay Singh.
index 0e7899f8f636bf178d4f919b719d2340d900867e..2c46649733bfa7dc1e71706b5909ed16172c382d 100644 (file)
@@ -147,6 +147,25 @@ class AutogenRenderTest(TestBase):
             "['active', 'code'], unique=False, somedialect_foobar='option')",
         )
 
+    @testing.emits_warning("Can't validate argument ")
+    def test_render_add_index_dialect_kwarg_with_columns(self):
+        """test that Column objects in dialect kwargs like
+        postgresql_include are rendered as column name strings,
+        not as raw Column repr.
+        """
+        t = self.table()
+        idx = Index(
+            "test_active_code_idx",
+            t.c.active,
+            somedialect_include=[t.c.code],
+        )
+        op_obj = ops.CreateIndexOp.from_index(idx)
+        eq_ignore_whitespace(
+            autogenerate.render_op_text(self.autogen_context, op_obj),
+            "op.create_index('test_active_code_idx', 'test', "
+            "['active'], unique=False, somedialect_include=['code'])",
+        )
+
     def test_render_add_index_batch(self):
         """
         autogenerate.render._add_index
@@ -316,6 +335,25 @@ class AutogenRenderTest(TestBase):
             "somedialect_foobar='option')",
         )
 
+    @testing.emits_warning("Can't validate argument ")
+    def test_render_drop_index_dialect_kwarg_with_columns(self):
+        """test that Column objects in dialect kwargs like
+        postgresql_include are rendered as column name strings
+        in drop_index, not as raw Column repr.
+        """
+        t = self.table()
+        idx = Index(
+            "test_active_code_idx",
+            t.c.active,
+            somedialect_include=(t.c.code,),
+        )
+        op_obj = ops.DropIndexOp.from_index(idx)
+        eq_ignore_whitespace(
+            autogenerate.render_op_text(self.autogen_context, op_obj),
+            "op.drop_index('test_active_code_idx', table_name='test', "
+            "somedialect_include=('code',))",
+        )
+
     def test_add_fk_constraint__dialect_kwargs(self):
         t1 = self.table()
         t2 = self.table()