From: Mike Bayer Date: Wed, 11 Oct 2017 13:53:22 +0000 (-0400) Subject: Clean up _fk_colspec() for link_to_name, no column found X-Git-Tag: rel_0_9_6~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a0524d734d31e0ecf6d6ee79d82077a20552a0d;p=thirdparty%2Fsqlalchemy%2Falembic.git Clean up _fk_colspec() for link_to_name, no column found A :class:`.ForeignKeyConstraint` can now render correctly if the ``link_to_name`` flag is set, as it will not attempt to resolve the name from a "key" in this case. Additionally, the constraint will render as-is even if the remote column name isn't present on the referenced remote table. Change-Id: Ic030fbc106973231b6877c1acfb5349e515335a8 Fixes: #456 --- diff --git a/alembic/autogenerate/render.py b/alembic/autogenerate/render.py index d6f398f5..0ba12dac 100644 --- a/alembic/autogenerate/render.py +++ b/alembic/autogenerate/render.py @@ -665,7 +665,7 @@ def _render_primary_key(constraint, autogen_context): def _fk_colspec(fk, metadata_schema): """Implement a 'safe' version of ForeignKey._get_colspec() that - never tries to resolve the remote table. + won't fail if the remote table can't be resolved. """ colspec = fk._get_colspec() @@ -677,12 +677,16 @@ def _fk_colspec(fk, metadata_schema): else: table_fullname = ".".join(tokens[0:-1]) - if fk.parent is not None and fk.parent.table is not None: - # try to resolve the remote table and adjust for column.key + if not fk.link_to_name and \ + fk.parent is not None and fk.parent.table is not None: + # try to resolve the remote table in order to adjust for column.key. + # the FK constraint needs to be rendered in terms of the column + # name. parent_metadata = fk.parent.table.metadata if table_fullname in parent_metadata.tables: - colname = _ident( - parent_metadata.tables[table_fullname].c[colname].name) + col = parent_metadata.tables[table_fullname].c.get(colname) + if col is not None: + colname = _ident(col.name) colspec = "%s.%s" % (table_fullname, colname) diff --git a/docs/build/unreleased/456.rst b/docs/build/unreleased/456.rst new file mode 100644 index 00000000..352608a5 --- /dev/null +++ b/docs/build/unreleased/456.rst @@ -0,0 +1,9 @@ +.. change:: + :tags: bug, autogenerate + :tickets: 456 + + A :class:`.ForeignKeyConstraint` can now render correctly if the + ``link_to_name`` flag is set, as it will not attempt to resolve the name + from a "key" in this case. Additionally, the constraint will render + as-is even if the remote column name isn't present on the referenced + remote table. \ No newline at end of file diff --git a/tests/test_autogen_render.py b/tests/test_autogen_render.py index dce7b715..c02157b8 100644 --- a/tests/test_autogen_render.py +++ b/tests/test_autogen_render.py @@ -1184,6 +1184,75 @@ class AutogenRenderTest(TestBase): "ondelete='CASCADE', initially='XYZ', deferrable=True)" ) + def test_render_fk_constraint_resolve_key(self): + m = MetaData() + t1 = Table('t', m, Column('c', Integer)) + t2 = Table('t2', m, Column('c_rem', Integer, key='c_remkey')) + + fk = ForeignKeyConstraint(['c'], ['t2.c_remkey']) + t1.append_constraint(fk) + + eq_ignore_whitespace( + re.sub( + r"u'", "'", + autogenerate.render._render_constraint( + fk, self.autogen_context)), + "sa.ForeignKeyConstraint(['c'], ['t2.c_rem'], )" + ) + + def test_render_fk_constraint_bad_table_resolve(self): + m = MetaData() + t1 = Table('t', m, Column('c', Integer)) + t2 = Table('t2', m, Column('c_rem', Integer)) + + fk = ForeignKeyConstraint(['c'], ['t2.nonexistent']) + t1.append_constraint(fk) + + eq_ignore_whitespace( + re.sub( + r"u'", "'", + autogenerate.render._render_constraint( + fk, self.autogen_context)), + "sa.ForeignKeyConstraint(['c'], ['t2.nonexistent'], )" + ) + + def test_render_fk_constraint_bad_table_resolve_dont_get_confused(self): + m = MetaData() + t1 = Table('t', m, Column('c', Integer)) + t2 = Table( + 't2', m, + Column('c_rem', Integer, key='cr_key'), + Column('c_rem_2', Integer, key='c_rem') + + ) + + fk = ForeignKeyConstraint(['c'], ['t2.c_rem'], link_to_name=True) + t1.append_constraint(fk) + + eq_ignore_whitespace( + re.sub( + r"u'", "'", + autogenerate.render._render_constraint( + fk, self.autogen_context)), + "sa.ForeignKeyConstraint(['c'], ['t2.c_rem'], )" + ) + + def test_render_fk_constraint_link_to_name(self): + m = MetaData() + t1 = Table('t', m, Column('c', Integer)) + t2 = Table('t2', m, Column('c_rem', Integer, key='c_remkey')) + + fk = ForeignKeyConstraint(['c'], ['t2.c_rem'], link_to_name=True) + t1.append_constraint(fk) + + eq_ignore_whitespace( + re.sub( + r"u'", "'", + autogenerate.render._render_constraint( + fk, self.autogen_context)), + "sa.ForeignKeyConstraint(['c'], ['t2.c_rem'], )" + ) + def test_render_fk_constraint_use_alter(self): m = MetaData() Table('t', m, Column('c', Integer))