- added 'checkfirst' argument to table.create()/table.drop(), as
well as table.exists() [ticket:234]
- some other ongoing fixes to inheritance [ticket:245]
+- attribute/backref/orphan/history-tracking tweaks as usual...
0.2.5
- fixed endless loop bug in select_by(), if the traversal hit
if callable_ is not None:
if passive:
return InstrumentedAttribute.PASSIVE_NORESULT
- l = InstrumentedList(self, obj, self._adapt_list(callable_()), init=False)
+ values = callable_()
+ l = InstrumentedList(self, obj, self._adapt_list(values), init=False)
+ if self.trackparent and values is not None:
+ [self.sethasparent(v, True) for v in values if v is not None]
# if a callable was executed, then its part of the "committed state"
# if any, so commit the newly loaded data
orig = state.get('original', None)
if callable_ is not None:
if passive:
return InstrumentedAttribute.PASSIVE_NORESULT
- obj.__dict__[self.key] = callable_()
+ value = callable_()
+ obj.__dict__[self.key] = value
+ if self.trackparent and value is not None:
+ self.sethasparent(value, True)
# if a callable was executed, then its part of the "committed state"
# if any, so commit the newly loaded data
orig = state.get('original', None)
class Post(object):pass
class Blog(object):pass
- manager.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'))
- manager.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'))
+ manager.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True)
+ manager.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True)
b = Blog()
(p1, p2, p3) = (Post(), Post(), Post())
b.posts.append(p1)
j.port = None
self.assert_(p.jack is None)
+ def testlazytrackparent(self):
+ """test that the "hasparent" flag works properly when lazy loaders and backrefs are used"""
+ manager = attributes.AttributeManager()
+
+ class Post(object):pass
+ class Blog(object):pass
+
+ # set up instrumented attributes with backrefs
+ manager.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True)
+ manager.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True)
+
+ # create objects as if they'd been freshly loaded from the database (without history)
+ b = Blog()
+ p1 = Post()
+ Blog.posts.set_callable(b, lambda:[p1])
+ Post.blog.set_callable(p1, lambda:b)
+
+ # assert connections
+ assert p1.blog is b
+ assert p1 in b.posts
+
+ # no orphans
+ assert getattr(Blog, 'posts').hasparent(p1)
+ assert getattr(Post, 'blog').hasparent(b)
+
+
def testinheritance(self):
"""tests that attributes are polymorphic"""
class Foo(object):pass