From 80c95fe17dde88e17686b7e199f2c0aafc734177 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Fri, 31 Oct 2025 22:35:49 -0400 Subject: [PATCH] add test for issue 1743 however this issue looks to be simple sqlite reflection issue on sqlalchemy side also fixes the incorrect exclusions code from 20c108720d7127ca. just skip entire test if SQLite fk reflection is not there. this exclusion should not have been added originally, it looks like this was mistaken for a limitation when it really was a bug in sqlite reflection Change-Id: I3f51ebaf01f41dba86cea0aa31be28334401887b --- alembic/testing/requirements.py | 4 + alembic/testing/suite/test_autogen_fks.py | 2 +- tests/requirements.py | 7 +- tests/test_autogen_diffs.py | 95 +++++++++++++++++++++++ 4 files changed, 104 insertions(+), 4 deletions(-) diff --git a/alembic/testing/requirements.py b/alembic/testing/requirements.py index 7ec026b4..1b217c93 100644 --- a/alembic/testing/requirements.py +++ b/alembic/testing/requirements.py @@ -164,6 +164,10 @@ class SuiteRequirements(Requirements): @property def fk_names(self): + return self.foreign_key_name_reflection + + @property + def foreign_key_name_reflection(self): return exclusions.open() @property diff --git a/alembic/testing/suite/test_autogen_fks.py b/alembic/testing/suite/test_autogen_fks.py index 355e244c..d69736e6 100644 --- a/alembic/testing/suite/test_autogen_fks.py +++ b/alembic/testing/suite/test_autogen_fks.py @@ -199,7 +199,7 @@ class AutogenerateForeignKeysTest(AutogenFixtureTest, TestBase): eq_(diffs, []) - @config.requirements.fk_names + @config.requirements.foreign_key_name_reflection def test_casing_convention_changed_so_put_drops_first(self): m1 = MetaData() m2 = MetaData() diff --git a/tests/requirements.py b/tests/requirements.py index b8c8a680..081e5f85 100644 --- a/tests/requirements.py +++ b/tests/requirements.py @@ -61,13 +61,14 @@ class DefaultRequirements(SuiteRequirements): return exclusions.only_on(["sqlite"]) @property - def fk_names(self): + def foreign_key_name_reflection(self): """backend can reflect foreign key names""" # issue here was fixed in SQLAlchemy #12954 for sqlite, 2.0 # release - return exclusions.fails_if( - lambda config: not sqla_compat.sqla_2 and config.against("sqlite") + return exclusions.skip_if( + lambda config: not sqla_compat.sqla_2 + and exclusions.against(config, "sqlite") ) @property diff --git a/tests/test_autogen_diffs.py b/tests/test_autogen_diffs.py index 174cfac5..cd9d54ae 100644 --- a/tests/test_autogen_diffs.py +++ b/tests/test_autogen_diffs.py @@ -1910,3 +1910,98 @@ class MultipleMetaDataTest(AutogenFixtureTest, TestBase): [m1a, m1b], [m2a, m2b], ) + + +class AutogenFKTest(AutogenFixtureTest, TestBase): + """Test foreign key constraint handling in autogenerate.""" + + __backend__ = True + __requires__ = ("foreign_key_constraint_reflection",) + + @testing.variation("case", ["uppercase", "lowercase"]) + @testing.variation("use_naming_convention", [True, False]) + @config.requirements.foreign_key_name_reflection + def test_drop_fk_with_mixed_case_name(self, case, use_naming_convention): + """Test #1743""" + if case.uppercase: + fk_pattern = ( + "FK_%(table_name)s_%(column_0_name)s_%(referred_table_name)s" + ) + expected_name = "FK_child_parent_id_parent" + else: + fk_pattern = ( + "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s" + ) + expected_name = "fk_child_parent_id_parent" + + if use_naming_convention: + m1 = MetaData(naming_convention={"fk": fk_pattern}) + else: + m1 = MetaData() + + Table( + "parent", + m1, + Column("id", Integer, primary_key=True), + Column("name", String(50)), + ) + + c = Table( + "child", + m1, + Column("id", Integer, primary_key=True), + Column("name", String(50)), + Column("parent_id", Integer), + ( + ForeignKeyConstraint(["parent_id"], ["parent.id"]) + if use_naming_convention + else ForeignKeyConstraint( + ["parent_id"], ["parent.id"], name=expected_name + ) + ), + ) + + eq_( + [ + fk + for fk in c.constraints + if isinstance(fk, ForeignKeyConstraint) + ][0].name, + expected_name, + ) + + if use_naming_convention: + m2 = MetaData(naming_convention={"fk": fk_pattern}) + else: + m2 = MetaData() + + Table( + "parent", + m2, + Column("id", Integer, primary_key=True), + Column("name", String(50)), + ) + + Table( + "child", + m2, + Column("id", Integer, primary_key=True), + Column("name", String(50)), + Column("parent_id", Integer), + ) + + diffs = self._fixture(m1, m2) + + # Should detect the FK removal + eq_(len(diffs), 1, f"Expected 1 diff, got {len(diffs)}: {diffs}") + + # Verify it's a remove_fk operation with the correct name + self._assert_fk_diff( + diffs[0], + "remove_fk", + "child", + ["parent_id"], + "parent", + ["id"], + name=expected_name, + ) -- 2.47.3