- Improved weakref identity map memory management to no longer
require mutexing, resurrects garbage collected instance
on a lazy basis for an InstanceState with pending changes.
-
+
+ - relation() won't hide unrelated ForeignKey errors inside of
+ the "please specify primaryjoin" message when determining
+ join condition.
+
- sql
- Further simplified SELECT compilation and its relationship
to result row processing.
class NoSuchColumnError(KeyError, InvalidRequestError):
"""A nonexistent column is requested from a ``RowProxy``."""
-class NoReferencedTableError(InvalidRequestError):
+class NoReferenceError(InvalidRequestError):
+ """Raised by ``ForeignKey`` to indicate a reference cannot be resolved."""
+
+class NoReferencedTableError(NoReferenceError):
"""Raised by ``ForeignKey`` when the referred ``Table`` cannot be located."""
+class NoReferencedColumnError(NoReferenceError):
+ """Raised by ``ForeignKey`` when the referred ``Column`` cannot be located."""
+
class NoSuchTableError(InvalidRequestError):
"""Table does not exist or is not visible to a connection."""
from sqlalchemy import sql, util, log
import sqlalchemy.exceptions as sa_exc
-from sqlalchemy.sql.util import ClauseAdapter, criterion_as_pairs
+from sqlalchemy.sql.util import ClauseAdapter, criterion_as_pairs, join_condition
from sqlalchemy.sql import operators, expression
from sqlalchemy.orm import (
attributes, dependency, mapper, object_mapper, strategies,
# found will try the more general mapped table, which in the case of inheritance
# is a join.
try:
- return sql.join(mapper.local_table, table)
+ return join_condition(mapper.local_table, table)
except sa_exc.ArgumentError, e:
- return sql.join(mapper.mapped_table, table)
+ return join_condition(mapper.mapped_table, table)
try:
if self.secondary is not None:
if self.secondaryjoin is None:
- self.secondaryjoin = _search_for_join(self.mapper, self.secondary).onclause
+ self.secondaryjoin = _search_for_join(self.mapper, self.secondary)
if self.primaryjoin is None:
- self.primaryjoin = _search_for_join(self.parent, self.secondary).onclause
+ self.primaryjoin = _search_for_join(self.parent, self.secondary)
else:
if self.primaryjoin is None:
- self.primaryjoin = _search_for_join(self.parent, self.target).onclause
+ self.primaryjoin = _search_for_join(self.parent, self.target)
except sa_exc.ArgumentError, e:
raise sa_exc.ArgumentError("Could not determine join condition between "
"parent/child tables on relation %s. "
else:
self._column = table.c[colname]
except KeyError, e:
- raise exc.ArgumentError(
+ raise exc.NoReferencedColumnError(
"Could not create ForeignKey '%s' on table '%s': "
"table '%s' has no column named '%s'" % (
self._colspec, parenttable.name, table.name, str(e)))
import testenv; testenv.configure_for_tests()
import datetime
from testlib import sa, testing
-from testlib.sa import Table, Column, Integer, String, ForeignKey
-from testlib.sa.orm import mapper, relation, backref, create_session
+from testlib.sa import Table, Column, Integer, String, ForeignKey, MetaData
+from testlib.sa.orm import mapper, relation, backref, create_session, compile_mappers, clear_mappers
from testlib.testing import eq_, startswith_
from orm import _base
sess.query(TagInstance).order_by(TagInstance.data).all(),
[TagInstance(data='iplc_case'), TagInstance(data='not_iplc_case')]
)
+
+
+class JoinConditionErrorTest(testing.TestBase):
+ def test_fk_error_raised(self):
+ m = MetaData()
+ t1 = Table('t1', m,
+ Column('id', Integer, primary_key=True),
+ Column('foo_id', Integer, ForeignKey('t2.nonexistent_id')),
+ )
+ t2 = Table('t2', m,
+ Column('id', Integer, primary_key=True),
+ )
+
+ t3 = Table('t3', m,
+ Column('id', Integer, primary_key=True),
+ Column('t1id', Integer, ForeignKey('t1.id'))
+ )
+
+ class C1(object):
+ pass
+ class C2(object):
+ pass
+
+ mapper(C1, t1, properties={'c2':relation(C2)})
+ mapper(C2, t3)
+
+ self.assertRaises(sa.exc.NoReferencedColumnError, compile_mappers)
+
+ def test_join_error_raised(self):
+ m = MetaData()
+ t1 = Table('t1', m,
+ Column('id', Integer, primary_key=True),
+ )
+ t2 = Table('t2', m,
+ Column('id', Integer, primary_key=True),
+ )
+
+ t3 = Table('t3', m,
+ Column('id', Integer, primary_key=True),
+ Column('t1id', Integer)
+ )
+
+ class C1(object):
+ pass
+ class C2(object):
+ pass
+
+ mapper(C1, t1, properties={'c2':relation(C2)})
+ mapper(C2, t3)
+
+ self.assertRaises(sa.exc.ArgumentError, compile_mappers)
+
+ def tearDown(self):
+ clear_mappers()
class TypeMatchTest(_base.MappedTest):
"""test errors raised when trying to add items whose type is not handled by a relation"""