From: Mike Bayer Date: Tue, 10 Jan 2012 16:43:47 +0000 (-0500) Subject: - Fixed regression from 0.6 whereby if X-Git-Tag: rel_0_7_5~55 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f2568b9bdedd12427aaaed393c68dcf20691ea11;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Fixed regression from 0.6 whereby if "load_on_pending" relationship() flag were used where a non-"get()" lazy clause needed to be emitted on a pending object, it would fail to load. --- diff --git a/CHANGES b/CHANGES index 2457c96689..fc72a7109c 100644 --- a/CHANGES +++ b/CHANGES @@ -23,6 +23,12 @@ CHANGES criteria which will join via AND, i.e. query.filter(x==y, z>q, ...) + - Fixed regression from 0.6 whereby if + "load_on_pending" relationship() flag were used + where a non-"get()" lazy clause needed to be + emitted on a pending object, it would fail + to load. + - engine - [bug] Added __reduce__ to StatementError, DBAPIError so that exceptions are pickleable, diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index aa744e0c1f..724e7dc2a0 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -305,18 +305,13 @@ class SQLCompiler(engine.Compiled): raise exc.InvalidRequestError( "A value is required for bind parameter %r" % bindparam.key) - elif bindparam.callable: - pd[name] = bindparam.callable() else: - pd[name] = bindparam.value + pd[name] = bindparam.effective_value return pd else: pd = {} for bindparam in self.bind_names: - if bindparam.callable: - pd[self.bind_names[bindparam]] = bindparam.callable() - else: - pd[self.bind_names[bindparam]] = bindparam.value + pd[self.bind_names[bindparam]] = bindparam.effective_value return pd params = property(construct_params, doc=""" diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 15d2970c20..9f2a161950 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -2606,6 +2606,21 @@ class _BindParamClause(ColumnElement): else: self.type = type_ + @property + def effective_value(self): + """Return the value of this bound parameter, + taking into account if the ``callable`` parameter + was set. + + The ``callable`` value will be evaluated + and returned if present, else ``value``. + + """ + if self.callable: + return self.callable() + else: + return self.value + def _clone(self): c = ClauseElement._clone(self) if self.unique: diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py index 33be99d874..97975441e4 100644 --- a/lib/sqlalchemy/sql/util.py +++ b/lib/sqlalchemy/sql/util.py @@ -152,13 +152,7 @@ def bind_values(clause): v = [] def visit_bindparam(bind): - value = bind.value - - # evaluate callables - if callable(value): - value = value() - - v.append(value) + v.append(bind.effective_value) visitors.traverse(clause, {}, {'bindparam':visit_bindparam}) return v diff --git a/test/orm/test_load_on_fks.py b/test/orm/test_load_on_fks.py index 697be27ff5..031ac66054 100644 --- a/test/orm/test_load_on_fks.py +++ b/test/orm/test_load_on_fks.py @@ -151,6 +151,25 @@ class LoadOnFKsTest(AssertsExecutionResults, fixtures.TestBase): # ...unless the flag is on assert c3.parent is p1 + def test_collection_load_from_pending_populated(self): + Parent.children.property.load_on_pending = True + p2 = Parent(id=p1.id) + sess.add(p2) + # load should emit since PK is populated + def go(): + assert p2.children + self.assert_sql_count(testing.db, go, 1) + + def test_collection_load_from_pending_no_sql(self): + Parent.children.property.load_on_pending = True + p2 = Parent(id=None) + sess.add(p2) + # load should not emit since "None" is the bound + # param list + def go(): + assert not p2.children + self.assert_sql_count(testing.db, go, 0) + def test_load_on_pending_with_set(self): Child.parent.property.load_on_pending = True