def test_collection_with_backref(self): for base in (object, MyBaseClass, MyClass): class Post(base):pass class Blog(base):pass attributes.register_class(Post) attributes.register_class(Blog) attributes.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True, useobject=True) attributes.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True, useobject=True) b = Blog() (p1, p2, p3) = (Post(), Post(), Post()) b.posts.append(p1) b.posts.append(p2) b.posts.append(p3) self.assert_(b.posts == [p1, p2, p3]) self.assert_(p2.blog is b) p3.blog = None self.assert_(b.posts == [p1, p2]) p4 = Post() p4.blog = b self.assert_(b.posts == [p1, p2, p4]) p4.blog = b p4.blog = b self.assert_(b.posts == [p1, p2, p4]) # assert no failure removing None p5 = Post() p5.blog = None del p5.blog
def test_inheritance(self): """tests that attributes are polymorphic""" for base in (object, MyBaseClass, MyClass): class Foo(base):pass class Bar(Foo):pass attributes.register_class(Foo) attributes.register_class(Bar) def func1(**kw): print "func1" return "this is the foo attr" def func2(**kw): print "func2" return "this is the bar attr" def func3(**kw): print "func3" return "this is the shared attr" attributes.register_attribute(Foo, 'element', uselist=False, callable_=lambda o:func1, useobject=True) attributes.register_attribute(Foo, 'element2', uselist=False, callable_=lambda o:func3, useobject=True) attributes.register_attribute(Bar, 'element', uselist=False, callable_=lambda o:func2, useobject=True) x = Foo() y = Bar() assert x.element == 'this is the foo attr' assert y.element == 'this is the bar attr', y.element assert x.element2 == 'this is the shared attr' assert y.element2 == 'this is the shared attr'
def test_basic(self): for base in (object, MyBaseClass, MyClass): class User(base): pass attributes.register_class(User) attributes.register_attribute(User, 'user_id', uselist=False, useobject=False) attributes.register_attribute(User, 'user_name', uselist=False, useobject=False) attributes.register_attribute(User, 'email_address', uselist=False, useobject=False) u = User() u.user_id = 7 u.user_name = 'john' u.email_address = '*****@*****.**' self.assert_(u.user_id == 7 and u.user_name == 'john' and u.email_address == '*****@*****.**') attributes.instance_state(u).commit_all() self.assert_(u.user_id == 7 and u.user_name == 'john' and u.email_address == '*****@*****.**') u.user_name = 'heythere' u.email_address = '*****@*****.**' self.assert_(u.user_id == 7 and u.user_name == 'heythere' and u.email_address == '*****@*****.**')
def test_dict_collections(self): class Foo(_base.BasicEntity): pass class Bar(_base.BasicEntity): pass from sqlalchemy.orm.collections import attribute_mapped_collection attributes.register_class(Foo) attributes.register_attribute(Foo, 'someattr', uselist=True, useobject=True, typecallable=attribute_mapped_collection('name')) hi = Bar(name='hi') there = Bar(name='there') old = Bar(name='old') new = Bar(name='new') f = Foo() eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), [], ())) f.someattr['hi'] = hi eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([hi], [], [])) f.someattr['there'] = there eq_(tuple([set(x) for x in attributes.get_history(attributes.instance_state(f), 'someattr')]), (set([hi, there]), set(), set())) attributes.instance_state(f).commit(['someattr']) eq_(tuple([set(x) for x in attributes.get_history(attributes.instance_state(f), 'someattr')]), (set(), set([hi, there]), set()))
def test_collections_via_backref(self): class Foo(_base.BasicEntity): pass class Bar(_base.BasicEntity): pass attributes.register_class(Foo) attributes.register_class(Bar) attributes.register_attribute(Foo, 'bars', uselist=True, extension=attributes.GenericBackrefExtension('foo'), trackparent=True, useobject=True) attributes.register_attribute(Bar, 'foo', uselist=False, extension=attributes.GenericBackrefExtension('bars'), trackparent=True, useobject=True) f1 = Foo() b1 = Bar() eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ((), [], ())) eq_(attributes.get_history(attributes.instance_state(b1), 'foo'), ((), [None], ())) #b1.foo = f1 f1.bars.append(b1) eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ([b1], [], [])) eq_(attributes.get_history(attributes.instance_state(b1), 'foo'), ([f1], (), ())) b2 = Bar() f1.bars.append(b2) eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ([b1, b2], [], [])) eq_(attributes.get_history(attributes.instance_state(b1), 'foo'), ([f1], (), ())) eq_(attributes.get_history(attributes.instance_state(b2), 'foo'), ([f1], (), ()))
def test_inheritance(self): """tests that attributes are polymorphic""" for base in (object, MyBaseClass, MyClass): class Foo(base):pass class Bar(Foo):pass attributes.register_class(Foo) attributes.register_class(Bar) def func1(): print "func1" return "this is the foo attr" def func2(): print "func2" return "this is the bar attr" def func3(): print "func3" return "this is the shared attr" attributes.register_attribute(Foo, 'element', uselist=False, callable_=lambda o:func1, useobject=True) attributes.register_attribute(Foo, 'element2', uselist=False, callable_=lambda o:func3, useobject=True) attributes.register_attribute(Bar, 'element', uselist=False, callable_=lambda o:func2, useobject=True) x = Foo() y = Bar() assert x.element == 'this is the foo attr' assert y.element == 'this is the bar attr', y.element assert x.element2 == 'this is the shared attr' assert y.element2 == 'this is the shared attr'
def test_dict_collections(self): class Foo(fixtures.Base): pass class Bar(fixtures.Base): pass from sqlalchemy.orm.collections import attribute_mapped_collection attributes.register_class(Foo) attributes.register_attribute(Foo, 'someattr', uselist=True, useobject=True, typecallable=attribute_mapped_collection('name')) hi = Bar(name='hi') there = Bar(name='there') old = Bar(name='old') new = Bar(name='new') f = Foo() self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [], [])) f.someattr['hi'] = hi self.assertEquals(attributes.get_history(f._state, 'someattr'), ([hi], [], [])) f.someattr['there'] = there self.assertEquals(tuple([set(x) for x in attributes.get_history(f._state, 'someattr')]), (set([hi, there]), set([]), set([]))) f._state.commit(['someattr']) self.assertEquals(tuple([set(x) for x in attributes.get_history(f._state, 'someattr')]), (set([]), set([hi, there]), set([])))
def test_standard(self): class A(object): pass attributes.register_class(A) eq_(type(attributes.manager_of_class(A)), attributes.ClassManager)
def test_list(self): class User(object):pass class Address(object):pass attributes.register_class(User) attributes.register_class(Address) attributes.register_attribute(User, 'user_id', uselist=False, useobject=False) attributes.register_attribute(User, 'user_name', uselist=False, useobject=False) attributes.register_attribute(User, 'addresses', uselist = True, useobject=True) attributes.register_attribute(Address, 'address_id', uselist=False, useobject=False) attributes.register_attribute(Address, 'email_address', uselist=False, useobject=False) u = User() u.user_id = 7 u.user_name = 'john' u.addresses = [] a = Address() a.address_id = 10 a.email_address = '*****@*****.**' u.addresses.append(a) self.assert_(u.user_id == 7 and u.user_name == 'john' and u.addresses[0].email_address == '*****@*****.**') u, attributes.instance_state(a).commit_all() self.assert_(u.user_id == 7 and u.user_name == 'john' and u.addresses[0].email_address == '*****@*****.**') u.user_name = 'heythere' a = Address() a.address_id = 11 a.email_address = '*****@*****.**' u.addresses.append(a) self.assert_(u.user_id == 7 and u.user_name == 'heythere' and u.addresses[0].email_address == '*****@*****.**' and u.addresses[1].email_address == '*****@*****.**')
def test_lazy_backref_collections(self): class Foo(_base.BasicEntity): pass class Bar(_base.BasicEntity): pass lazy_load = [] def lazyload(instance): def load(): return lazy_load return load attributes.register_class(Foo) attributes.register_class(Bar) attributes.register_attribute(Foo, 'bars', uselist=True, extension=attributes.GenericBackrefExtension('foo'), trackparent=True, callable_=lazyload, useobject=True) attributes.register_attribute(Bar, 'foo', uselist=False, extension=attributes.GenericBackrefExtension('bars'), trackparent=True, useobject=True) bar1, bar2, bar3, bar4 = [Bar(id=1), Bar(id=2), Bar(id=3), Bar(id=4)] lazy_load = [bar1, bar2, bar3] f = Foo() bar4 = Bar() bar4.foo = f eq_(attributes.get_history(attributes.instance_state(f), 'bars'), ([bar4], [bar1, bar2, bar3], [])) lazy_load = None f = Foo() bar4 = Bar() bar4.foo = f eq_(attributes.get_history(attributes.instance_state(f), 'bars'), ([bar4], [], [])) lazy_load = [bar1, bar2, bar3] attributes.instance_state(f).expire_attributes(['bars']) eq_(attributes.get_history(attributes.instance_state(f), 'bars'), ((), [bar1, bar2, bar3], ()))
def test_lazyhistory(self): """tests that history functions work with lazy-loading attributes""" class Foo(_base.BasicEntity): pass class Bar(_base.BasicEntity): pass attributes.register_class(Foo) attributes.register_class(Bar) bar1, bar2, bar3, bar4 = [Bar(id=1), Bar(id=2), Bar(id=3), Bar(id=4)] def func1(): return "this is func 1" def func2(): return [bar1, bar2, bar3] attributes.register_attribute(Foo, 'col1', uselist=False, callable_=lambda o:func1, useobject=True) attributes.register_attribute(Foo, 'col2', uselist=True, callable_=lambda o:func2, useobject=True) attributes.register_attribute(Bar, 'id', uselist=False, useobject=True) x = Foo() attributes.instance_state(x).commit_all() x.col2.append(bar4) eq_(attributes.get_history(attributes.instance_state(x), 'col2'), ([bar4], [bar1, bar2, bar3], []))
def test_lazytrackparent(self): """test that the "hasparent" flag works properly when lazy loaders and backrefs are used""" class Post(object):pass class Blog(object):pass attributes.register_class(Post) attributes.register_class(Blog) # set up instrumented attributes with backrefs attributes.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True, useobject=True) attributes.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), trackparent=True, useobject=True) # create objects as if they'd been freshly loaded from the database (without history) b = Blog() p1 = Post() attributes.instance_state(b).set_callable('posts', lambda:[p1]) attributes.instance_state(p1).set_callable('blog', lambda:b) p1, attributes.instance_state(b).commit_all() # no orphans (called before the lazy loaders fire off) assert attributes.has_parent(Blog, p1, 'posts', optimistic=True) assert attributes.has_parent(Post, b, 'blog', optimistic=True) # assert connections assert p1.blog is b assert p1 in b.posts # manual connections b2 = Blog() p2 = Post() b2.posts.append(p2) assert attributes.has_parent(Blog, p2, 'posts') assert attributes.has_parent(Post, b2, 'blog')
def test_defaulted_init(self): class X(object): def __init__(self_, a, b=123, c='abc'): self_.a = a self_.b = b self_.c = c attributes.register_class(X) o = X('foo') eq_(o.a, 'foo') eq_(o.b, 123) eq_(o.c, 'abc') class Y(object): unique = object() class OutOfScopeForEval(object): def __repr__(self_): # misleading repr return '123' outofscope = OutOfScopeForEval() def __init__(self_, u=unique, o=outofscope): self_.u = u self_.o = o attributes.register_class(Y) o = Y() assert o.u is Y.unique assert o.o is Y.outofscope
def test_parenttrack(self): class Foo(object):pass class Bar(object):pass attributes.register_class(Foo) attributes.register_class(Bar) attributes.register_attribute(Foo, 'element', uselist=False, trackparent=True, useobject=True) attributes.register_attribute(Bar, 'element', uselist=False, trackparent=True, useobject=True) f1 = Foo() f2 = Foo() b1 = Bar() b2 = Bar() f1.element = b1 b2.element = f2 assert attributes.has_parent(Foo, b1, 'element') assert not attributes.has_parent(Foo, b2, 'element') assert not attributes.has_parent(Foo, f2, 'element') assert attributes.has_parent(Bar, f2, 'element') b2.element = None assert not attributes.has_parent(Bar, f2, 'element') # test that double assignment doesn't accidentally reset the 'parent' flag. b3 = Bar() f4 = Foo() b3.element = f4 assert attributes.has_parent(Bar, f4, 'element') b3.element = f4 assert attributes.has_parent(Bar, f4, 'element')
def test_collections_via_backref(self): class Foo(fixtures.Base): pass class Bar(fixtures.Base): pass attributes.register_class(Foo) attributes.register_class(Bar) attributes.register_attribute(Foo, 'bars', uselist=True, extension=attributes.GenericBackrefExtension('foo'), trackparent=True, useobject=True) attributes.register_attribute(Bar, 'foo', uselist=False, extension=attributes.GenericBackrefExtension('bars'), trackparent=True, useobject=True) f1 = Foo() b1 = Bar() self.assertEquals(attributes.get_history(f1._state, 'bars'), ([], [], [])) self.assertEquals(attributes.get_history(b1._state, 'foo'), ([], [None], [])) #b1.foo = f1 f1.bars.append(b1) self.assertEquals(attributes.get_history(f1._state, 'bars'), ([b1], [], [])) self.assertEquals(attributes.get_history(b1._state, 'foo'), ([f1], [], [])) b2 = Bar() f1.bars.append(b2) self.assertEquals(attributes.get_history(f1._state, 'bars'), ([b1, b2], [], [])) self.assertEquals(attributes.get_history(b1._state, 'foo'), ([f1], [], [])) self.assertEquals(attributes.get_history(b2._state, 'foo'), ([f1], [], []))
def setUp(self): global Post, Blog, called, lazy_load class Post(object): def __init__(self, name): self.name = name __hash__ = None def __eq__(self, other): return other.name == self.name class Blog(object): def __init__(self, name): self.name = name __hash__ = None def __eq__(self, other): return other.name == self.name called = [0] lazy_load = [] def lazy_posts(instance): def load(): called[0] += 1 return lazy_load return load attributes.register_class(Post) attributes.register_class(Blog) attributes.register_attribute(Post, 'blog', uselist=False, extension=attributes.GenericBackrefExtension('posts'), trackparent=True, useobject=True) attributes.register_attribute(Blog, 'posts', uselist=True, extension=attributes.GenericBackrefExtension('blog'), callable_=lazy_posts, trackparent=True, useobject=True)
def test_nativeext_submanager(self): class Mine(attributes.ClassManager): pass class A(object): __sa_instrumentation_manager__ = Mine attributes.register_class(A) eq_(type(attributes.manager_of_class(A)), Mine)
def test_instance_dict(self): class User(MyClass): pass attributes.register_class(User) attributes.register_attribute(User, 'user_id', uselist=False, useobject=False) attributes.register_attribute(User, 'user_name', uselist=False, useobject=False) attributes.register_attribute(User, 'email_address', uselist=False, useobject=False) u = User() u.user_id = 7 u.user_name = 'john' u.email_address = '*****@*****.**' self.assert_( u.__dict__ == { '_my_state': u._my_state, '_goofy_dict': { 'user_id': 7, 'user_name': 'john', 'email_address': '*****@*****.**' } })
def test_customfinder_pass(self): class A(object): pass def find(cls): return None attributes.instrumentation_finders.insert(0, find) attributes.register_class(A) eq_(type(attributes.manager_of_class(A)), attributes.ClassManager)
def register(self, cls, canary): original_init = cls.__init__ attributes.register_class(cls) ne_(cls.__init__, original_init) manager = attributes.manager_of_class(cls) def on_init(state, instance, args, kwargs): canary.append((cls, 'on_init', type(instance))) manager.events.add_listener('on_init', on_init)
def test_pickleness(self): attributes.register_class(MyTest) attributes.register_class(MyTest2) attributes.register_attribute(MyTest, 'user_id', uselist=False, useobject=False) attributes.register_attribute(MyTest, 'user_name', uselist=False, useobject=False) attributes.register_attribute(MyTest, 'email_address', uselist=False, useobject=False) attributes.register_attribute(MyTest2, 'a', uselist=False, useobject=False) attributes.register_attribute(MyTest2, 'b', uselist=False, useobject=False) # shouldnt be pickling callables at the class level def somecallable(*args): return None attr_name = 'mt2' attributes.register_attribute(MyTest, attr_name, uselist = True, trackparent=True, callable_=somecallable, useobject=True) o = MyTest() o.mt2.append(MyTest2()) o.user_id=7 o.mt2[0].a = 'abcde' pk_o = pickle.dumps(o) o2 = pickle.loads(pk_o) pk_o2 = pickle.dumps(o2) # so... pickle is creating a new 'mt2' string after a roundtrip here, # so we'll brute-force set it to be id-equal to the original string if False: o_mt2_str = [ k for k in o.__dict__ if k == 'mt2'][0] o2_mt2_str = [ k for k in o2.__dict__ if k == 'mt2'][0] self.assert_(o_mt2_str == o2_mt2_str) self.assert_(o_mt2_str is not o2_mt2_str) # change the id of o2.__dict__['mt2'] former = o2.__dict__['mt2'] del o2.__dict__['mt2'] o2.__dict__[o_mt2_str] = former self.assert_(pk_o == pk_o2) # the above is kind of distrurbing, so let's do it again a little # differently. the string-id in serialization thing is just an # artifact of pickling that comes up in the first round-trip. # a -> b differs in pickle memoization of 'mt2', but b -> c will # serialize identically. o3 = pickle.loads(pk_o2) pk_o3 = pickle.dumps(o3) o4 = pickle.loads(pk_o3) pk_o4 = pickle.dumps(o4) self.assert_(pk_o3 == pk_o4) # and lastly make sure we still have our data after all that. # identical serialzation is great, *if* it's complete :) self.assert_(o4.user_id == 7) self.assert_(o4.user_name is None) self.assert_(o4.email_address is None) self.assert_(len(o4.mt2) == 1) self.assert_(o4.mt2[0].a == 'abcde') self.assert_(o4.mt2[0].b is None)
def test_scalar(self): class Foo(_base.BasicEntity): pass attributes.register_class(Foo) attributes.register_attribute(Foo, 'someattr', uselist=False, useobject=False) # case 1. new object f = Foo() eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), (), ())) f.someattr = "hi" eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), (['hi'], (), ())) attributes.instance_state(f).commit(['someattr']) eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), ['hi'], ())) f.someattr = 'there' eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), (['there'], (), ['hi'])) attributes.instance_state(f).commit(['someattr']) eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), ['there'], ())) del f.someattr eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), (), ['there'])) # case 2. object with direct dictionary settings (similar to a load operation) f = Foo() f.__dict__['someattr'] = 'new' eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), ['new'], ())) f.someattr = 'old' eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), (['old'], (), ['new'])) attributes.instance_state(f).commit(['someattr']) eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), ['old'], ())) # setting None on uninitialized is currently a change for a scalar attribute # no lazyload occurs so this allows overwrite operation to proceed f = Foo() eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), (), ())) f.someattr = None eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([None], (), ())) f = Foo() f.__dict__['someattr'] = 'new' eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), ['new'], ())) f.someattr = None eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([None], (), ['new'])) # set same value twice f = Foo() attributes.instance_state(f).commit(['someattr']) f.someattr = 'one' eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), (['one'], (), ())) f.someattr = 'two' eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), (['two'], (), ()))
def test_null_instrumentation(self): class Foo(MyBaseClass): pass attributes.register_class(Foo) attributes.register_attribute(Foo, "name", uselist=False, useobject=False) attributes.register_attribute(Foo, "bars", uselist=True, trackparent=True, useobject=True) assert Foo.name == attributes.manager_of_class(Foo)['name'] assert Foo.bars == attributes.manager_of_class(Foo)['bars']
def test_single_down(self): class A(object): pass attributes.register_class(A) mgr_factory = lambda cls: attributes.ClassManager(cls) class B(A): __sa_instrumentation_manager__ = staticmethod(mgr_factory) assert_raises_message(TypeError, "multiple instrumentation implementations", attributes.register_class, B)
def test_deferred(self): for base in (object, MyBaseClass, MyClass): class Foo(base): pass data = {'a': 'this is a', 'b': 12} def loader(state, keys): for k in keys: state.dict[k] = data[k] return attributes.ATTR_WAS_SET attributes.register_class(Foo) manager = attributes.manager_of_class(Foo) manager.deferred_scalar_loader = loader attributes.register_attribute(Foo, 'a', uselist=False, useobject=False) attributes.register_attribute(Foo, 'b', uselist=False, useobject=False) assert Foo in attributes.instrumentation_registry._state_finders f = Foo() attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) f.a = "this is some new a" attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) f.a = "this is another new a" eq_(f.a, "this is another new a") eq_(f.b, 12) attributes.instance_state(f).expire_attributes( attributes.instance_dict(f), None) eq_(f.a, "this is a") eq_(f.b, 12) del f.a eq_(f.a, None) eq_(f.b, 12) attributes.instance_state(f).commit_all( attributes.instance_dict(f)) eq_(f.a, None) eq_(f.b, 12)
def test_single_up(self): class A(object): pass # delay registration mgr_factory = lambda cls: attributes.ClassManager(cls) class B(A): __sa_instrumentation_manager__ = staticmethod(mgr_factory) attributes.register_class(B) assert_raises(TypeError, attributes.register_class, A)
def test_diamond_b2(self): mgr_factory = lambda cls: attributes.ClassManager(cls) class A(object): pass class B1(A): pass class B2(A): __sa_instrumentation_manager__ = staticmethod(mgr_factory) class C(object): pass attributes.register_class(B2) assert_raises_message(TypeError, "multiple instrumentation implementations", attributes.register_class, B1)
def test_diamond_c_b(self): mgr_factory = lambda cls: attributes.ClassManager(cls) class A(object): pass class B1(A): pass class B2(A): __sa_instrumentation_manager__ = mgr_factory class C(object): pass attributes.register_class(C) assert_raises(TypeError, attributes.register_class, B1)
def test_single_down(self): class A(object): pass attributes.register_class(A) mgr_factory = lambda cls: attributes.ClassManager(cls) class B(A): __sa_instrumentation_manager__ = staticmethod(mgr_factory) assert_raises(TypeError, attributes.register_class, B)
def test_subclassed(self): class MyEvents(attributes.Events): pass class MyClassManager(attributes.ClassManager): event_registry_factory = MyEvents attributes.instrumentation_finders.insert(0, lambda cls: MyClassManager) class A(object): pass attributes.register_class(A) manager = attributes.manager_of_class(A) assert isinstance(manager.events, MyEvents)
def test_scalar(self): class Foo(fixtures.Base): pass attributes.register_class(Foo) attributes.register_attribute(Foo, 'someattr', uselist=False, useobject=False) # case 1. new object f = Foo() self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [], [])) f.someattr = "hi" self.assertEquals(attributes.get_history(f._state, 'someattr'), (['hi'], [], [])) f._state.commit(['someattr']) self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], ['hi'], [])) f.someattr = 'there' self.assertEquals(attributes.get_history(f._state, 'someattr'), (['there'], [], ['hi'])) f._state.commit(['someattr']) self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], ['there'], [])) del f.someattr self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [], ['there'])) # case 2. object with direct dictionary settings (similar to a load operation) f = Foo() f.__dict__['someattr'] = 'new' self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], ['new'], [])) f.someattr = 'old' self.assertEquals(attributes.get_history(f._state, 'someattr'), (['old'], [], ['new'])) f._state.commit(['someattr']) self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], ['old'], [])) # setting None on uninitialized is currently a change for a scalar attribute # no lazyload occurs so this allows overwrite operation to proceed f = Foo() self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [], [])) f.someattr = None self.assertEquals(attributes.get_history(f._state, 'someattr'), ([None], [], [])) f = Foo() f.__dict__['someattr'] = 'new' self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], ['new'], [])) f.someattr = None self.assertEquals(attributes.get_history(f._state, 'someattr'), ([None], [], ['new']))
def test_collectionclasses(self): class Foo(object):pass attributes.register_class(Foo) attributes.register_attribute(Foo, "collection", uselist=True, typecallable=set, useobject=True) assert isinstance(Foo().collection, set) attributes.unregister_attribute(Foo, "collection") try: attributes.register_attribute(Foo, "collection", uselist=True, typecallable=dict, useobject=True) assert False except exceptions.ArgumentError, e: assert str(e) == "Type InstrumentedDict must elect an appender method to be a collection class"
def test_instance_dict(self): class User(MyClass): pass attributes.register_class(User) attributes.register_attribute(User, 'user_id', uselist = False, useobject=False) attributes.register_attribute(User, 'user_name', uselist = False, useobject=False) attributes.register_attribute(User, 'email_address', uselist = False, useobject=False) u = User() u.user_id = 7 u.user_name = 'john' u.email_address = '*****@*****.**' self.assert_(u.__dict__ == {'_my_state':u._my_state, '_goofy_dict':{'user_id':7, 'user_name':'john', 'email_address':'*****@*****.**'}}, u.__dict__)
def test_object_collections_set(self): class Foo(_base.BasicEntity): pass class Bar(_base.BasicEntity): def __nonzero__(self): assert False attributes.register_class(Foo) attributes.register_attribute(Foo, 'someattr', uselist=True, useobject=True) hi = Bar(name='hi') there = Bar(name='there') old = Bar(name='old') new = Bar(name='new') # case 1. new object f = Foo() eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), [], ())) f.someattr = [hi] eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([hi], [], [])) attributes.instance_state(f).commit(['someattr']) eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), [hi], ())) f.someattr = [there] eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([there], [], [hi])) attributes.instance_state(f).commit(['someattr']) eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), [there], ())) f.someattr = [hi] eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([hi], [], [there])) f.someattr = [old, new] eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([old, new], [], [there])) # case 2. object with direct settings (similar to a load operation) f = Foo() collection = attributes.init_collection(attributes.instance_state(f), 'someattr') collection.append_without_event(new) attributes.instance_state(f).commit_all() eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), [new], ())) f.someattr = [old] eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ([old], [], [new])) attributes.instance_state(f).commit(['someattr']) eq_(attributes.get_history(attributes.instance_state(f), 'someattr'), ((), [old], ()))
def test_object_collections_set(self): class Foo(fixtures.Base): pass class Bar(fixtures.Base): def __nonzero__(self): assert False attributes.register_class(Foo) attributes.register_attribute(Foo, 'someattr', uselist=True, useobject=True) hi = Bar(name='hi') there = Bar(name='there') old = Bar(name='old') new = Bar(name='new') # case 1. new object f = Foo() self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [], [])) f.someattr = [hi] self.assertEquals(attributes.get_history(f._state, 'someattr'), ([hi], [], [])) f._state.commit(['someattr']) self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [hi], [])) f.someattr = [there] self.assertEquals(attributes.get_history(f._state, 'someattr'), ([there], [], [hi])) f._state.commit(['someattr']) self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [there], [])) f.someattr = [hi] self.assertEquals(attributes.get_history(f._state, 'someattr'), ([hi], [], [there])) f.someattr = [old, new] self.assertEquals(attributes.get_history(f._state, 'someattr'), ([old, new], [], [there])) # case 2. object with direct settings (similar to a load operation) f = Foo() collection = attributes.init_collection(f, 'someattr') collection.append_without_event(new) f._state.commit_all() self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [new], [])) f.someattr = [old] self.assertEquals(attributes.get_history(f._state, 'someattr'), ([old], [], [new])) f._state.commit(['someattr']) self.assertEquals(attributes.get_history(f._state, 'someattr'), ([], [old], []))
def test_onetoone(self): class Port(object):pass class Jack(object):pass attributes.register_class(Port) attributes.register_class(Jack) attributes.register_attribute(Port, 'jack', uselist=False, extension=attributes.GenericBackrefExtension('port'), useobject=True) attributes.register_attribute(Jack, 'port', uselist=False, extension=attributes.GenericBackrefExtension('jack'), useobject=True) p = Port() j = Jack() p.jack = j self.assert_(j.port is p) self.assert_(p.jack is not None) j.port = None self.assert_(p.jack is None)
def test_single_up(self): class A(object): pass # delay registration mgr_factory = lambda cls: attributes.ClassManager(cls) class B(A): __sa_instrumentation_manager__ = staticmethod(mgr_factory) attributes.register_class(B) assert_raises_message(TypeError, "multiple instrumentation implementations", attributes.register_class, A)
def test_register_reserved_attribute(self): class T(object): pass attributes.register_class(T) manager = attributes.manager_of_class(T) sa = attributes.ClassManager.STATE_ATTR ma = attributes.ClassManager.MANAGER_ATTR fails = lambda method, attr: assert_raises( KeyError, getattr(manager, method), attr, property()) fails('install_member', sa) fails('install_member', ma) fails('install_descriptor', sa) fails('install_descriptor', ma)
def test_uninstrument(self): class A(object): pass manager = attributes.register_class(A) assert attributes.manager_of_class(A) is manager attributes.unregister_class(A) assert attributes.manager_of_class(A) is None
def test_alternate_finders(self): """Ensure the generic finder front-end deals with edge cases.""" class Unknown(object): pass class Known(MyBaseClass): pass attributes.register_class(Known) k, u = Known(), Unknown() assert attributes.manager_of_class(Unknown) is None assert attributes.manager_of_class(Known) is not None assert attributes.manager_of_class(None) is None assert attributes.instance_state(k) is not None assert_raises((AttributeError, KeyError), attributes.instance_state, u) assert_raises((AttributeError, KeyError), attributes.instance_state, None)
def test_basic(self): import pickle global A class A(object): pass def canary(instance): assert False try: attributes.register_class(A) manager = attributes.manager_of_class(A) manager.events.add_listener('on_load', canary) a = A() p_a = pickle.dumps(a) re_a = pickle.loads(p_a) finally: del A
def test_history(self): for base in (object, MyBaseClass, MyClass): class Foo(base): pass class Bar(base): pass attributes.register_class(Foo) attributes.register_class(Bar) attributes.register_attribute(Foo, "name", uselist=False, useobject=False) attributes.register_attribute(Foo, "bars", uselist=True, trackparent=True, useobject=True) attributes.register_attribute(Bar, "name", uselist=False, useobject=False) f1 = Foo() f1.name = 'f1' eq_(attributes.get_history(attributes.instance_state(f1), 'name'), (['f1'], (), ())) b1 = Bar() b1.name = 'b1' f1.bars.append(b1) eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ([b1], [], [])) attributes.instance_state(f1).commit_all(attributes.instance_dict(f1)) attributes.instance_state(b1).commit_all(attributes.instance_dict(b1)) eq_(attributes.get_history(attributes.instance_state(f1), 'name'), ((), ['f1'], ())) eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ((), [b1], ())) f1.name = 'f1mod' b2 = Bar() b2.name = 'b2' f1.bars.append(b2) eq_(attributes.get_history(attributes.instance_state(f1), 'name'), (['f1mod'], (), ['f1'])) eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ([b2], [b1], [])) f1.bars.remove(b1) eq_(attributes.get_history(attributes.instance_state(f1), 'bars'), ([b2], [], [b1]))
def test_none(self): class A(object): pass attributes.register_class(A) mgr_factory = lambda cls: attributes.ClassManager(cls) class B(object): __sa_instrumentation_manager__ = staticmethod(mgr_factory) attributes.register_class(B) class C(object): __sa_instrumentation_manager__ = attributes.ClassManager attributes.register_class(C)
def test_nativeext_interfaceexact(self): class A(object): __sa_instrumentation_manager__ = sa.orm.interfaces.InstrumentationManager attributes.register_class(A) ne_(type(attributes.manager_of_class(A)), attributes.ClassManager)