From: Mike Bayer Date: Thu, 21 Jul 2011 15:44:41 +0000 (-0400) Subject: - Added an informative error message when X-Git-Tag: rel_0_6_9~42 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=ba40767d23e4ad488d1e6a2ad3c366036a50ee18;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Added an informative error message when ForeignKeyConstraint refers to a column name in the parent that is not found. - add tests for [ticket:2226], as if we hit each @declared_attr directly with obj.__get__(obj, name) instead of using getattr(cls, name). Basic inheritance mechanics are improperly used in this case, so 2226 is invalid. --- diff --git a/CHANGES b/CHANGES index bfe5ceaafd..7feaca8cc0 100644 --- a/CHANGES +++ b/CHANGES @@ -48,6 +48,11 @@ CHANGES when used with certain dialects. This bug is not in 0.7. +- schema + - Added an informative error message when + ForeignKeyConstraint refers to a column name in + the parent that is not found. + - oracle - Added ORA-00028 to disconnect codes, use cx_oracle _Error.code to get at the code, diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 6c73aabfa3..0ab90380d2 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -1802,7 +1802,13 @@ class ForeignKeyConstraint(Constraint): # string-specified column names now get # resolved to Column objects if isinstance(col, basestring): - col = table.c[col] + try: + col = table.c[col] + except KeyError: + raise exc.ArgumentError( + "Can't create ForeignKeyConstraint " + "on table '%s': no column " + "named '%s' is present." % (table.description, col)) fk._set_parent(col) if self.use_alter: diff --git a/test/engine/test_metadata.py b/test/engine/test_metadata.py index f4678cb185..2773e31dec 100644 --- a/test/engine/test_metadata.py +++ b/test/engine/test_metadata.py @@ -146,6 +146,39 @@ class MetaDataTest(TestBase, ComparesTables): fk1 = ForeignKeyConstraint(('foo', ), ('bar', ), table=t1) assert fk1 in t1.constraints + def test_fk_no_such_parent_col_error(self): + meta = MetaData() + a = Table('a', meta, Column('a', Integer)) + b = Table('b', meta, Column('b', Integer)) + + def go(): + a.append_constraint( + ForeignKeyConstraint(['x'], ['b.b']) + ) + assert_raises_message( + exc.ArgumentError, + "Can't create ForeignKeyConstraint on " + "table 'a': no column named 'x' is present.", + go + ) + + def test_fk_no_such_target_col_error(self): + meta = MetaData() + a = Table('a', meta, Column('a', Integer)) + b = Table('b', meta, Column('b', Integer)) + a.append_constraint( + ForeignKeyConstraint(['a'], ['b.x']) + ) + + def go(): + list(a.c.a.foreign_keys)[0].column + assert_raises_message( + exc.NoReferencedColumnError, + "Could not create ForeignKey 'b.x' on " + "table 'a': table 'b' has no column named 'x'", + go + ) + @testing.exclude('mysql', '<', (4, 1, 1), 'early types are squirrely') def test_to_metadata(self): meta = MetaData() diff --git a/test/ext/test_declarative.py b/test/ext/test_declarative.py index d47dda75f5..a67e72c9cd 100644 --- a/test/ext/test_declarative.py +++ b/test/ext/test_declarative.py @@ -3023,6 +3023,40 @@ class DeclarativeMixinTest(DeclarativeTestBase): eq_(Model.__table__.c.keys(), ['col1', 'col3', 'col2', 'col4', 'id']) + def test_honor_class_mro_one(self): + class HasXMixin(object): + @declared_attr + def x(self): + return Column(Integer) + + class Parent(HasXMixin, Base): + __tablename__ = 'parent' + id = Column(Integer, primary_key=True) + + class Child(Parent): + __tablename__ = 'child' + id = Column(Integer, ForeignKey('parent.id'), primary_key=True) + + assert "x" not in Child.__table__.c + + def test_honor_class_mro_two(self): + class HasXMixin(object): + @declared_attr + def x(self): + return Column(Integer) + + class Parent(HasXMixin, Base): + __tablename__ = 'parent' + id = Column(Integer, primary_key=True) + def x(self): + return "hi" + + class C(Parent): + __tablename__ = 'c' + id = Column(Integer, ForeignKey('parent.id'), primary_key=True) + + assert C().x() == 'hi' + class DeclarativeMixinPropertyTest(DeclarativeTestBase): def test_column_property(self):