summaryrefslogtreecommitdiff
path: root/test/orm/test_attributes.py
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2009-09-12 19:59:39 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2009-09-12 19:59:39 +0000
commitf83c9a3959e25e5817bae6f0ca0015f9054baf8d (patch)
tree66eaaa8bf55df63ce3ef0267b6462eac673f6743 /test/orm/test_attributes.py
parent6a8b52c4069886d8223b97ea6fc5ef65eb4dcc8d (diff)
downloadsqlalchemy-f83c9a3959e25e5817bae6f0ca0015f9054baf8d.tar.gz
- Added an assertion that prevents a @validates function
or other AttributeExtension from loading an unloaded collection such that internal state may be corrupted. [ticket:1526]
Diffstat (limited to 'test/orm/test_attributes.py')
-rw-r--r--test/orm/test_attributes.py43
1 files changed, 42 insertions, 1 deletions
diff --git a/test/orm/test_attributes.py b/test/orm/test_attributes.py
index b481b0679..99f0a49d3 100644
--- a/test/orm/test_attributes.py
+++ b/test/orm/test_attributes.py
@@ -4,7 +4,7 @@ from sqlalchemy.orm.collections import collection
from sqlalchemy.orm.interfaces import AttributeExtension
from sqlalchemy import exc as sa_exc
from sqlalchemy.test import *
-from sqlalchemy.test.testing import eq_
+from sqlalchemy.test.testing import eq_, assert_raises
from test.orm import _base
from sqlalchemy.test.util import gc_collect
from sqlalchemy.util import cmp, jython
@@ -220,7 +220,48 @@ class AttributesTest(_base.ORMTest):
a.email_address = 'foo@bar.com'
u.addresses.append(a)
self.assert_(u.user_id == 7 and u.user_name == 'heythere' and u.addresses[0].email_address == 'lala@123.com' and u.addresses[1].email_address == 'foo@bar.com')
+
+ def test_extension_lazyload_assertion(self):
+ class Foo(_base.BasicEntity):
+ pass
+ class Bar(_base.BasicEntity):
+ pass
+
+ class ReceiveEvents(AttributeExtension):
+ def append(self, state, child, initiator):
+ state.obj().bars
+ return child
+
+ def remove(self, state, child, initiator):
+ state.obj().bars
+ return child
+
+ def set(self, state, child, oldchild, initiator):
+ return child
+ attributes.register_class(Foo)
+ attributes.register_class(Bar)
+
+ bar1, bar2, bar3 = [Bar(id=1), Bar(id=2), Bar(id=3)]
+ def func1(**kw):
+ if kw.get('passive') is attributes.PASSIVE_NO_FETCH:
+ return attributes.PASSIVE_NO_RESULT
+
+ return [bar1, bar2, bar3]
+
+ attributes.register_attribute(Foo, 'bars', uselist=True, callable_=lambda o:func1, useobject=True, extension=[ReceiveEvents()])
+ attributes.register_attribute(Bar, 'foos', uselist=True, useobject=True, extension=[attributes.GenericBackrefExtension('bars')])
+
+ x = Foo()
+ assert_raises(AssertionError, Bar(id=4).foos.append, x)
+
+ x.bars
+ b = Bar(id=4)
+ b.foos.append(x)
+ attributes.instance_state(x).expire_attributes(['bars'])
+ assert_raises(AssertionError, b.foos.remove, x)
+
+
def test_scalar_listener(self):
# listeners on ScalarAttributeImpl and MutableScalarAttributeImpl aren't used normally.
# test that they work for the benefit of user extensions