]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
[Fixes #1671] Passthrough `dialect_kwargs` to `ops.create_foreign_key()` to enable...
authorJustin Malin <justin@joincandidhealth.com>
Fri, 6 Jun 2025 20:36:53 +0000 (20:36 +0000)
committerJustin Malin <justin@joincandidhealth.com>
Fri, 6 Jun 2025 20:39:29 +0000 (20:39 +0000)
alembic/autogenerate/render.py
tests/test_postgresql.py

index 4bad437a263397908cf0c283d14d1a6684f2ac85..d5ca2f4faca03090f20739b4ae5507b673077a7a 100644 (file)
@@ -18,6 +18,7 @@ from mako.pygen import PythonPrinter
 from sqlalchemy import schema as sa_schema
 from sqlalchemy import sql
 from sqlalchemy import types as sqltypes
+from sqlalchemy.sql.base import _DialectArgView
 from sqlalchemy.sql.elements import conv
 from sqlalchemy.sql.elements import Label
 from sqlalchemy.sql.elements import quoted_name
@@ -121,6 +122,15 @@ def _render_cmd_body(
     return buf.getvalue()
 
 
+def _render_dialect_kwargs_items(
+        autogen_context: AutogenContext, dialect_kwargs: _DialectArgView
+) -> list[str]:
+    return [
+        f"{key}={_render_potential_expr(val, autogen_context)}"
+        for key, val in dialect_kwargs.items()
+    ]
+
+
 def render_op(
     autogen_context: AutogenContext, op: ops.MigrateOperation
 ) -> List[str]:
@@ -303,15 +313,6 @@ def _drop_table(autogen_context: AutogenContext, op: ops.DropTableOp) -> str:
     return text
 
 
-def _render_dialect_kwargs_items(
-    autogen_context: AutogenContext, item: DialectKWArgs
-) -> list[str]:
-    return [
-        f"{key}={_render_potential_expr(val, autogen_context)}"
-        for key, val in item.dialect_kwargs.items()
-    ]
-
-
 @renderers.dispatch_for(ops.CreateIndexOp)
 def _add_index(autogen_context: AutogenContext, op: ops.CreateIndexOp) -> str:
     index = op.to_index()
@@ -331,7 +332,7 @@ def _add_index(autogen_context: AutogenContext, op: ops.CreateIndexOp) -> str:
 
     assert index.table is not None
 
-    opts = _render_dialect_kwargs_items(autogen_context, index)
+    opts = _render_dialect_kwargs_items(autogen_context, index.dialect_kwargs)
     if op.if_not_exists is not None:
         opts.append("if_not_exists=%r" % bool(op.if_not_exists))
     text = tmpl % {
@@ -365,7 +366,7 @@ def _drop_index(autogen_context: AutogenContext, op: ops.DropIndexOp) -> str:
             "%(prefix)sdrop_index(%(name)r, "
             "table_name=%(table_name)r%(schema)s%(kwargs)s)"
         )
-    opts = _render_dialect_kwargs_items(autogen_context, index)
+    opts = _render_dialect_kwargs_items(autogen_context, index.dialect_kwargs)
     if op.if_exists is not None:
         opts.append("if_exists=%r" % bool(op.if_exists))
     text = tmpl % {
@@ -418,9 +419,15 @@ def _add_fk_constraint(
             if value is not None:
                 args.append("%s=%r" % (k, value))
 
-    return "%(prefix)screate_foreign_key(%(args)s)" % {
+
+    # op.to_constraint() may fail with `multiple values for argument 'name'`.
+    dialect_kwarg_view = getattr(op.kw, "dialect_kwargs", {})
+    dialect_kwargs = _render_dialect_kwargs_items(autogen_context, dialect_kwarg_view)
+
+    return "%(prefix)screate_foreign_key(%(args)s%(dialect_kwargs)s)" % {
         "prefix": _alembic_autogenerate_prefix(autogen_context),
         "args": ", ".join(args),
+        "dialect_kwargs": ", " + ", ".join(dialect_kwargs) if dialect_kwargs else "",
     }
 
 
@@ -664,7 +671,7 @@ def _uq_constraint(
         opts.append(
             ("name", _render_gen_name(autogen_context, constraint.name))
         )
-    dialect_options = _render_dialect_kwargs_items(autogen_context, constraint)
+    dialect_options = _render_dialect_kwargs_items(autogen_context, constraint.dialect_kwargs)
 
     if alter:
         args = [repr(_render_gen_name(autogen_context, constraint.name))]
index 44f422dd52e8fb61cdacdf82bae5e7304b37deb0..289090df1e276d96e048e2bd618563109ad51766 100644 (file)
@@ -133,6 +133,11 @@ class PostgresqlOpTest(TestBase):
         op.create_index("i", "t", ["c1", "c2"], if_not_exists=True)
         context.assert_("CREATE INDEX IF NOT EXISTS i ON t (c1, c2)")
 
+    def test_create_fk_postgresql_not_valid(self):
+        context = op_fixture("postgresql")
+        op.create_foreign_key("i", "t1", "t2", ["c1"], ["c2"], postgresql_not_valid=True)
+        context.assert_("ALTER TABLE t1 ADD CONSTRAINT i FOREIGN KEY(c1) REFERENCES t2 (c2) NOT VALID")
+
     @config.combinations("include_table", "no_table", argnames="include_table")
     def test_drop_index_postgresql_concurrently(self, include_table):
         context = op_fixture("postgresql")