Commits

Mike Bayer committed 67647db

- [bug] An error is emitted when uselist=False
is combined with a "dynamic" loader.
This is a warning in 0.7.9.

Comments (0)

Files changed (4)

     or remove operation is received on the
     now-detached collection.  [ticket:2476]
 
+  - [bug] An error is emitted when uselist=False
+    is combined with a "dynamic" loader.
+    This is a warning in 0.7.9.
+
   - [removed] Deprecated identifiers removed:
 
     * allow_null_pks mapper() argument
     disabled on subclasses, unless overridden
     explicitly.
 
+  - [bug] A warning is emitted when lazy='dynamic'
+    is combined with uselist=False.  This is an
+    exception raise in 0.8.
+
 - sql
   - [bug] Fixed CTE bug whereby positional
     bound parameters present in the CTEs themselves

doc/build/orm/collections.rst

    The :func:`~.orm.dynamic_loader` function is essentially the same
    as :func:`~.orm.relationship` with the ``lazy='dynamic'`` argument specified.
 
+.. warning::
+
+   The "dynamic" loader applies to **collections only**.   It is not valid
+   to use "dynamic" loaders with many-to-one, one-to-one, or uselist=False
+   relationships.   Newer versions of SQLAlchemy emit warnings or exceptions
+   in these cases.
 
 Setting Noload
 ---------------

lib/sqlalchemy/orm/dynamic.py

 
 """
 
-from .. import log, util
+from .. import log, util, exc
 from ..sql import operators
 from . import (
     attributes, object_session, util as orm_util, strategies,
 class DynaLoader(strategies.AbstractRelationshipLoader):
     def init_class_attribute(self, mapper):
         self.is_class_level = True
-
+        if not self.uselist:
+            raise exc.InvalidRequestError(
+                    "On relationship %s, 'dynamic' loaders cannot be used with "
+                    "many-to-one/one-to-one relationships and/or "
+                    "uselist=False." % self.parent_property)
         strategies._register_attribute(self,
             mapper,
             useobject=True,

test/orm/test_dynamic.py

 from test.lib.testing import eq_, ne_
 import operator
-from sqlalchemy.orm import dynamic_loader, backref
+from sqlalchemy.orm import dynamic_loader, backref, configure_mappers
 from test.lib import testing
-from sqlalchemy import Integer, String, ForeignKey, desc, select, func
+from sqlalchemy import Integer, String, ForeignKey, desc, select, func, exc
 from test.lib.schema import Table, Column
 from sqlalchemy.orm import mapper, relationship, create_session, Query, attributes, exc as orm_exc
 from sqlalchemy.orm.dynamic import AppenderMixin
                                 self.classes.User)
 
         mapper(User, users, properties={
-            'addresses':dynamic_loader(mapper(Address, addresses))
+            'addresses': dynamic_loader(mapper(Address, addresses))
         })
         sess = create_session()
         u = sess.query(User).get(8)
             email_address='e'
         )
 
+    def test_no_uselist_false(self):
+        users, Address, addresses, User = (self.tables.users,
+                                self.classes.Address,
+                                self.tables.addresses,
+                                self.classes.User)
+        mapper(Address, addresses)
+        mapper(User, users, properties={
+                "addresses": relationship(Address, lazy='dynamic', uselist=False)
+            })
+        assert_raises_message(
+            exc.InvalidRequestError,
+            "On relationship User.addresses, 'dynamic' loaders cannot be "
+            "used with many-to-one/one-to-one relationships and/or "
+            "uselist=False.",
+            configure_mappers
+        )
+
+    def test_no_m2o(self):
+        users, Address, addresses, User = (self.tables.users,
+                                self.classes.Address,
+                                self.tables.addresses,
+                                self.classes.User)
+        mapper(Address, addresses, properties={
+                'user': relationship(User, lazy='dynamic')
+            })
+        mapper(User, users)
+        assert_raises_message(
+            exc.InvalidRequestError,
+            "On relationship Address.user, 'dynamic' loaders cannot be "
+            "used with many-to-one/one-to-one relationships and/or "
+            "uselist=False.",
+            configure_mappers
+        )
+
     def test_order_by(self):
         users, Address, addresses, User = (self.tables.users,
                                 self.classes.Address,