Mike Bayer avatar Mike Bayer committed 8576acc

- Fixed bug whereby mapper couldn't initialize if a composite
primary key referenced another table that was not defined
yet [ticket:1161]

Comments (0)

Files changed (4)

     - The `echo_uow` flag on `Session` is deprecated, and unit-of-work
       logging is now application-level only, not per-session level.
+- declarative
+    - Fixed bug whereby mapper couldn't initialize if a composite
+      primary key referenced another table that was not defined
+      yet [ticket:1161]
 - schema
     - Added "sorted_tables" accessor to MetaData, which returns


             # determine primary key from argument or mapped_table pks - reduce to the minimal set of columns
             if self.primary_key_argument:
                 primary_key = sqlutil.reduce_columns(
-                    self.mapped_table.corresponding_column(c)
-                    for c in self.primary_key_argument)
+                    [self.mapped_table.corresponding_column(c) for c in self.primary_key_argument], 
+                    ignore_nonexistent_tables=True)
                 primary_key = sqlutil.reduce_columns(
-                    self._pks_by_table[self.mapped_table])
+                    self._pks_by_table[self.mapped_table], ignore_nonexistent_tables=True)
             if len(primary_key) == 0:
                 raise sa_exc.ArgumentError("Mapper %s could not assemble any primary key columns for mapped table '%s'" % (self, self.mapped_table.description))


     return ret
-def reduce_columns(columns, *clauses):
+def reduce_columns(columns, *clauses, **kw):
     """given a list of columns, return a 'reduced' set based on natural equivalents.
     the set is reduced to the smallest list of columns which have no natural
     \*clauses is an optional list of join clauses which will be traversed
     to further identify columns that are "equivalent".
+    \**kw may specify 'ignore_nonexistent_tables' to ignore foreign keys
+    whose tables are not yet configured.
     This function is primarily used to determine the most minimal "primary key"
     from a selectable, by reducing the set of primary key columns present
     in the the selectable to just those that are not repeated.
+    ignore_nonexistent_tables = kw.pop('ignore_nonexistent_tables', False)
     columns = util.OrderedSet(columns)
     omit = set()
             for c in columns:
                 if c is col:
-                if fk.column.shares_lineage(c):
+                try:
+                    fk_col = fk.column
+                except exc.NoReferencedTableError:
+                    if ignore_nonexistent_tables:
+                        continue
+                    else:
+                        raise
+                if fk_col.shares_lineage(c):


+    def test_pk_with_fk_init(self):
+        class Bar(Base):
+            __tablename__ = 'bar'
+            id = sa.Column(sa.Integer, sa.ForeignKey("foo.id"), primary_key=True)
+            ex = sa.Column(sa.Integer, primary_key=True)
+        class Foo(Base):
+            __tablename__ = 'foo'
+            id = sa.Column(sa.Integer, primary_key=True)
+            bars = sa.orm.relation(Bar)
+        assert Bar.__mapper__.primary_key[0] is Bar.__table__.c.id
+        assert Bar.__mapper__.primary_key[1] is Bar.__table__.c.ex
     def test_single_inheritance(self):
         class Company(Base, ComparableEntity):
             __tablename__ = 'companies'
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.