]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Added an informative error message when
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 21 Jul 2011 15:44:31 +0000 (11:44 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 21 Jul 2011 15:44:31 +0000 (11:44 -0400)
    ForeignKeyConstraint refers to a column name in
    the parent that is not found.  Also in 0.6.9.
- 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.

CHANGES
lib/sqlalchemy/ext/declarative.py
lib/sqlalchemy/schema.py
test/ext/test_declarative.py
test/sql/test_metadata.py

diff --git a/CHANGES b/CHANGES
index 660482e606971c51e9708f90283884bcd8847249..41f624af8d9dab4bbc52c4b85f20328e2a0dabf7 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -99,6 +99,10 @@ CHANGES
     loses itself.  Affects [ticket:2188].
 
 - schema
+  - Added an informative error message when 
+    ForeignKeyConstraint refers to a column name in 
+    the parent that is not found.  Also in 0.6.9.
+
   - Fixed bug whereby adaptation of old append_ddl_listener()
     function was passing unexpected **kw through 
     to the Table event.   Table gets no kws, the MetaData
index 8c26edf5cdceaedcebeffeede19bd19e658a4538..15e7ba34f094895d5091291d211975bfc356b3f5 100755 (executable)
@@ -944,7 +944,6 @@ def _as_declarative(cls, classname, dict_):
                 continue
             elif base is not cls:
                 # we're a mixin.
-
                 if isinstance(obj, Column):
                     if obj.foreign_keys:
                         raise exc.InvalidRequestError(
@@ -1042,7 +1041,6 @@ def _as_declarative(cls, classname, dict_):
             if key == c.key:
                 del our_stuff[key]
     cols = sorted(cols, key=lambda c:c._creation_order)
-
     table = None
     if '__table__' not in dict_:
         if tablename is not None:
index 1763dc484d164233c8deab61587016312baba163..25c7e30a203b0a455153e313d5e1d6816a302f7b 100644 (file)
@@ -2008,7 +2008,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))
 
             if not hasattr(fk, 'parent') or \
                 fk.parent is not col:
index 1adaf6e5fa98da3271f964a6bf88d6ef69996395..22733223ded516e2d92f696951525ff7b4e44592 100644 (file)
@@ -3176,6 +3176,41 @@ 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):
index ea18229def721baf31b4341ad8f5fb42fcce4784..406db27a7a8f51814411f2266a09a0d65d5d1a11 100644 (file)
@@ -195,6 +195,39 @@ class MetaDataTest(fixtures.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()