def test_partially_mapped_inheritance(self): class A(object): pass class B(A): pass class C(B): def __init__(self, x): pass m = mapper(A, self.fixture()) a = attributes.instance_state(A()) assert isinstance(a, attributes.InstanceState) assert type(a) is not attributes.InstanceState b = attributes.instance_state(B()) assert isinstance(b, attributes.InstanceState) assert type(b) is not attributes.InstanceState # B is not mapped in the current implementation self.assertRaises(sa.orm.exc.UnmappedClassError, class_mapper, B) # the constructor of C is decorated too. # we don't support unmapped subclasses in any case, # users should not be expecting any particular behavior # from this scenario. c = attributes.instance_state(C(3)) assert isinstance(c, attributes.InstanceState) assert type(c) is not attributes.InstanceState # C is not mapped in the current implementation self.assertRaises(sa.orm.exc.UnmappedClassError, class_mapper, C)
def test_partially_mapped_inheritance(self): class A(object): pass class B(A): pass class C(B): def __init__(self): pass mapper(A, self.fixture()) a = attributes.instance_state(A()) assert isinstance(a, attributes.InstanceState) assert type(a) is not attributes.InstanceState b = attributes.instance_state(B()) assert isinstance(b, attributes.InstanceState) assert type(b) is not attributes.InstanceState # C is unmanaged cobj = C() self.assertRaises((AttributeError, TypeError), attributes.instance_state, cobj)
def test_expire_cascade(self): mapper(User, users, properties={ 'addresses':relation(Address, cascade="all, refresh-expire") }) mapper(Address, addresses) s = create_session() u = s.query(User).get(8) assert u.addresses[0].email_address == '*****@*****.**' u.addresses[0].email_address = 'someotheraddress' s.expire(u) u.name print attributes.instance_state(u).dict assert u.addresses[0].email_address == '*****@*****.**'
def test_partial_expire(self): mapper(Order, orders) sess = create_session() o = sess.query(Order).get(3) sess.expire(o, attribute_names=['description']) assert 'id' in o.__dict__ assert 'description' not in o.__dict__ assert attributes.instance_state(o).dict['isopen'] == 1 orders.update(orders.c.id == 3).execute(description='order 3 modified') def go(): assert o.description == 'order 3 modified' self.assert_sql_count(testing.db, go, 1) assert attributes.instance_state( o).dict['description'] == 'order 3 modified' o.isopen = 5 sess.expire(o, attribute_names=['description']) assert 'id' in o.__dict__ assert 'description' not in o.__dict__ assert o.__dict__['isopen'] == 5 assert attributes.instance_state(o).committed_state['isopen'] == 1 def go(): assert o.description == 'order 3 modified' self.assert_sql_count(testing.db, go, 1) assert o.__dict__['isopen'] == 5 assert attributes.instance_state( o).dict['description'] == 'order 3 modified' assert attributes.instance_state(o).committed_state['isopen'] == 1 sess.flush() sess.expire(o, attribute_names=['id', 'isopen', 'description']) assert 'id' not in o.__dict__ assert 'isopen' not in o.__dict__ assert 'description' not in o.__dict__ def go(): assert o.description == 'order 3 modified' assert o.id == 3 assert o.isopen == 5 self.assert_sql_count(testing.db, go, 1)
def test_basic(self): class A(_fixtures.Base): pass class B(_fixtures.Base): pass mapper(A, table_a, properties={ 'bs':relation(B, cascade="all, delete-orphan") }) mapper(B, table_b) a1 = A(name='a1', bs=[B(name='b1'), B(name='b2'), B(name='b3')]) sess = create_session() sess.add(a1) sess.flush() sess.clear() eq_(sess.query(A).get(a1.id), A(name='a1', bs=[B(name='b1'), B(name='b2'), B(name='b3')])) a1 = sess.query(A).get(a1.id) assert not class_mapper(B)._is_orphan( attributes.instance_state(a1.bs[0])) a1.bs[0].foo='b2modified' a1.bs[1].foo='b3modified' sess.flush() sess.clear() eq_(sess.query(A).get(a1.id), A(name='a1', bs=[B(name='b1'), B(name='b2'), B(name='b3')]))
def test_basic(self): class A(_fixtures.Base): pass class B(_fixtures.Base): pass mapper(A, table_a, properties={"bs": relation(B, cascade="all, delete-orphan")}) mapper(B, table_b) a1 = A(name="a1", bs=[B(name="b1"), B(name="b2"), B(name="b3")]) sess = create_session() sess.add(a1) sess.flush() sess.expunge_all() eq_(sess.query(A).get(a1.id), A(name="a1", bs=[B(name="b1"), B(name="b2"), B(name="b3")])) a1 = sess.query(A).get(a1.id) assert not class_mapper(B)._is_orphan(attributes.instance_state(a1.bs[0])) a1.bs[0].foo = "b2modified" a1.bs[1].foo = "b3modified" sess.flush() sess.expunge_all() eq_(sess.query(A).get(a1.id), A(name="a1", bs=[B(name="b1"), B(name="b2"), B(name="b3")]))
def test_expire_cascade(self): mapper(User, users, properties={ 'addresses': relation(Address, cascade="all, refresh-expire") }) mapper(Address, addresses) s = create_session() u = s.query(User).get(8) assert u.addresses[0].email_address == '*****@*****.**' u.addresses[0].email_address = 'someotheraddress' s.expire(u) u.name print attributes.instance_state(u).dict assert u.addresses[0].email_address == '*****@*****.**'
def test_partial_expire(self): mapper(Order, orders) sess = create_session() o = sess.query(Order).get(3) sess.expire(o, attribute_names=['description']) assert 'id' in o.__dict__ assert 'description' not in o.__dict__ assert attributes.instance_state(o).dict['isopen'] == 1 orders.update(orders.c.id==3).execute(description='order 3 modified') def go(): assert o.description == 'order 3 modified' self.assert_sql_count(testing.db, go, 1) assert attributes.instance_state(o).dict['description'] == 'order 3 modified' o.isopen = 5 sess.expire(o, attribute_names=['description']) assert 'id' in o.__dict__ assert 'description' not in o.__dict__ assert o.__dict__['isopen'] == 5 assert attributes.instance_state(o).committed_state['isopen'] == 1 def go(): assert o.description == 'order 3 modified' self.assert_sql_count(testing.db, go, 1) assert o.__dict__['isopen'] == 5 assert attributes.instance_state(o).dict['description'] == 'order 3 modified' assert attributes.instance_state(o).committed_state['isopen'] == 1 sess.flush() sess.expire(o, attribute_names=['id', 'isopen', 'description']) assert 'id' not in o.__dict__ assert 'isopen' not in o.__dict__ assert 'description' not in o.__dict__ def go(): assert o.description == 'order 3 modified' assert o.id == 3 assert o.isopen == 5 self.assert_sql_count(testing.db, go, 1)
def __eq__(self, other): """'passively' compare this object to another. only look at attributes that are present on the source object. """ if self in _recursion_stack: return True _recursion_stack.add(self) try: # pick the entity thats not SA persisted as the source try: state = attributes.instance_state(self) key = state.key except (KeyError, AttributeError): key = None if other is None: a = self b = other elif key is not None: a = other b = self else: a = self b = other for attr in a.__dict__.keys(): if attr[0] == '_': continue value = getattr(a, attr) #print "looking at attr:", attr, "start value:", value if hasattr(value, '__iter__') and not isinstance(value, basestring): try: # catch AttributeError so that lazy loaders trigger battr = getattr(b, attr) except AttributeError: #print "b class does not have attribute named '%s'" % attr #raise return False if list(value) == list(battr): continue else: return False else: if value is not None: if value != getattr(b, attr, None): #print "2. Attribute named '%s' does not match that of b" % attr return False else: return True finally: _recursion_stack.remove(self)
def test_expire(self): mapper(User, users, properties={ 'addresses': relation(Address, backref='user'), }) mapper(Address, addresses) sess = create_session() u = sess.query(User).get(7) assert len(u.addresses) == 1 u.name = 'foo' del u.addresses[0] sess.expire(u) assert 'name' not in u.__dict__ def go(): assert u.name == 'jack' self.assert_sql_count(testing.db, go, 1) assert 'name' in u.__dict__ u.name = 'foo' sess.flush() # change the value in the DB users.update(users.c.id == 7, values=dict(name='jack')).execute() sess.expire(u) # object isnt refreshed yet, using dict to bypass trigger assert u.__dict__.get('name') != 'jack' assert 'name' in attributes.instance_state(u).expired_attributes sess.query(User).all() # test that it refreshed assert u.__dict__['name'] == 'jack' assert 'name' not in attributes.instance_state(u).expired_attributes def go(): assert u.name == 'jack' self.assert_sql_count(testing.db, go, 0)
def test_rebuild_state(self): """not much of a 'test', but illustrate how to remove instance-level state before pickling. """ mapper(User, users) u1 = User() attributes.manager_of_class(User).teardown_instance(u1) assert not u1.__dict__ u2 = pickle.loads(pickle.dumps(u1)) attributes.manager_of_class(User).setup_instance(u2) assert attributes.instance_state(u2)
def test_expire_committed(self): """test that the committed state of the attribute receives the most recent DB data""" mapper(Order, orders) sess = create_session() o = sess.query(Order).get(3) sess.expire(o) orders.update(id=3).execute(description='order 3 modified') assert o.isopen == 1 assert attributes.instance_state(o).dict['description'] == 'order 3 modified' def go(): sess.flush() self.assert_sql_count(testing.db, go, 0)
def test_expire(self): mapper(User, users, properties={ 'addresses':relation(Address, backref='user'), }) mapper(Address, addresses) sess = create_session() u = sess.query(User).get(7) assert len(u.addresses) == 1 u.name = 'foo' del u.addresses[0] sess.expire(u) assert 'name' not in u.__dict__ def go(): assert u.name == 'jack' self.assert_sql_count(testing.db, go, 1) assert 'name' in u.__dict__ u.name = 'foo' sess.flush() # change the value in the DB users.update(users.c.id==7, values=dict(name='jack')).execute() sess.expire(u) # object isnt refreshed yet, using dict to bypass trigger assert u.__dict__.get('name') != 'jack' assert 'name' in attributes.instance_state(u).expired_attributes sess.query(User).all() # test that it refreshed assert u.__dict__['name'] == 'jack' assert 'name' not in attributes.instance_state(u).expired_attributes def go(): assert u.name == 'jack' self.assert_sql_count(testing.db, go, 0)
def test_no_instance_key(self): # this tests an artificial condition such that # an instance is pending, but has expired attributes. this # is actually part of a larger behavior when postfetch needs to # occur during a flush() on an instance that was just inserted mapper(User, users) sess = create_session() u = sess.query(User).get(7) sess.expire(u, attribute_names=['name']) sess.expunge(u) attributes.instance_state(u).key = None assert 'name' not in u.__dict__ sess.add(u) assert u.name == 'jack'
def test_expire_committed(self): """test that the committed state of the attribute receives the most recent DB data""" mapper(Order, orders) sess = create_session() o = sess.query(Order).get(3) sess.expire(o) orders.update(id=3).execute(description='order 3 modified') assert o.isopen == 1 assert attributes.instance_state( o).dict['description'] == 'order 3 modified' def go(): sess.flush() self.assert_sql_count(testing.db, go, 0)