def test_no_orphan(self): """test that a lazily loaded child object is not marked as an orphan""" users, Address, addresses, User = ( self.tables.users, self.classes.Address, self.tables.addresses, self.classes.User, ) mapper( User, users, properties={ "addresses": relationship(Address, cascade="all,delete-orphan", lazy="select") }, ) mapper(Address, addresses) sess = create_session() user = sess.query(User).get(7) assert getattr(User, "addresses").hasparent(attributes.instance_state( user.addresses[0]), optimistic=True) assert not sa.orm.class_mapper(Address)._is_orphan( attributes.instance_state(user.addresses[0]))
def test_pending_combines_with_flushed(self): """test the combination of unflushed pending + lazy loaded from DB.""" Item, Keyword = (self.classes.Item, self.classes.Keyword) session = Session(testing.db, autoflush=False) k1 = Keyword(name="k1") k2 = Keyword(name="k2") i1 = Item(description="i1", keywords=[k1]) session.add(i1) session.add(k2) session.commit() k2.items.append(i1) # the pending # list is still here. eq_( set( attributes.instance_state( i1)._pending_mutations["keywords"].added_items), set([k2]), ) # because autoflush is off, k2 is still # coming in from pending eq_(i1.keywords, [k1, k2]) # prove it didn't flush eq_(session.scalar("select count(*) from item_keywords"), 1) # the pending collection was removed assert ("keywords" not in attributes.instance_state(i1)._pending_mutations)
def _fixture(self): A, B = self.classes.A, self.classes.B session = create_session() uowcommit = self._get_test_uow(session) a_mapper = class_mapper(A) b_mapper = class_mapper(B) self.a1 = a1 = A() self.b1 = b1 = B() uowcommit = self._get_test_uow(session) return ( uowcommit, attributes.instance_state(a1), attributes.instance_state(b1), a_mapper, b_mapper, )
def test_history_populated_passive_return_never_set(self): User, Address, sess, a1 = self._u_ad_fixture(True) eq_( Address.user.impl.get_history( attributes.instance_state(a1), attributes.instance_dict(a1), passive=attributes.PASSIVE_RETURN_NEVER_SET, ), ((), [User(name="ed")], ()), )
def test_history_empty_passive_return_never_set(self): User, Address, sess, a1 = self._u_ad_fixture(False) eq_( Address.user.impl.get_history( attributes.instance_state(a1), attributes.instance_dict(a1), passive=attributes.PASSIVE_RETURN_NEVER_SET, ), ((), (), ()), ) assert "user_id" not in a1.__dict__ assert "user" not in a1.__dict__
def test_get_empty_passive_no_initialize(self): User, Address, sess, a1 = self._u_ad_fixture(False) eq_( Address.user.impl.get( attributes.instance_state(a1), attributes.instance_dict(a1), passive=attributes.PASSIVE_NO_INITIALIZE, ), attributes.PASSIVE_NO_RESULT, ) assert "user_id" not in a1.__dict__ assert "user" not in a1.__dict__
def test_history_populated_passive_no_initialize(self): User, Address, sess, a1 = self._u_ad_fixture(True) eq_( Address.user.impl.get_history( attributes.instance_state(a1), attributes.instance_dict(a1), passive=attributes.PASSIVE_NO_INITIALIZE, ), attributes.HISTORY_BLANK, ) assert "user_id" not in a1.__dict__ assert "user" not in a1.__dict__
def test_basic(self): for base in (object, MyBaseClass, MyClass): class User(base): pass 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 = "*****@*****.**" eq_(u.user_id, 7) eq_(u.user_name, "john") eq_(u.email_address, "*****@*****.**") attributes.instance_state(u)._commit_all( attributes.instance_dict(u)) eq_(u.user_id, 7) eq_(u.user_name, "john") eq_(u.email_address, "*****@*****.**") u.user_name = "heythere" u.email_address = "*****@*****.**" eq_(u.user_id, 7) eq_(u.user_name, "heythere") eq_(u.email_address, "*****@*****.**")
def test_exceptions(self): class Foo(object): pass users = self.tables.users mapper(User, users) for sa_exc in ( orm_exc.UnmappedInstanceError(Foo()), orm_exc.UnmappedClassError(Foo), orm_exc.ObjectDeletedError(attributes.instance_state(User())), ): for loads, dumps in picklers(): repickled = loads(dumps(sa_exc)) eq_(repickled.args[0], sa_exc.args[0])
def test_rebuild_state(self): """not much of a 'test', but illustrate how to remove instance-level state before pickling. """ users = self.tables.users 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_alternate_finders(self): """Ensure the generic finder front-end deals with edge cases.""" class Unknown(object): pass class Known(MyBaseClass): pass register_class(Known) k, u = Known(), Unknown() assert instrumentation.manager_of_class(Unknown) is None assert instrumentation.manager_of_class(Known) is not None assert instrumentation.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_stale_state_positive_pk_change(self): """Illustrate that we can't easily link a stale state to a fresh one if the fresh one has a PK change (unless we a. tracked all the previous PKs, wasteful, or b. recycled states - time consuming, breaks lots of edge cases, destabilizes the code) """ User = self.classes.User s, u1, a1 = self._fixture() s._expunge_states([attributes.instance_state(u1)]) del u1 gc_collect() u1 = s.query(User).first() # primary key change. now we # can't rely on state.key as the # identifier. new_id = u1.id + 10 u1.id = new_id a1.user_id = new_id s.flush() assert_raises_message( orm_exc.StaleDataError, "can't be sure this is the most recent parent.", u1.addresses.remove, a1, ) # u1.addresses wasn't actually impacted, because the event was # caught before collection mutation eq_(u1.addresses, [a1]) # expire all and we can continue s.expire_all() u1.addresses.remove(a1) self._assert_not_hasparent(a1)
def test_stale_state_negative(self): User = self.classes.User s, u1, a1 = self._fixture() u2 = User(addresses=[a1]) s.add(u2) s.flush() s._expunge_states([attributes.instance_state(u2)]) del u2 gc_collect() assert_raises_message( orm_exc.StaleDataError, "can't be sure this is the most recent parent.", u1.addresses.remove, a1, ) s.flush() self._assert_hasparent(a1)
def test_instance_state(self): User = self.classes.User u1 = User() insp = inspect(u1) is_(insp, instance_state(u1))
def test_multi_level_no_base(self): pjoin = polymorphic_union( { "manager": managers_table, "engineer": engineers_table, "hacker": hackers_table, }, "type", "pjoin", ) pjoin2 = polymorphic_union( { "engineer": engineers_table, "hacker": hackers_table }, "type", "pjoin2", ) employee_mapper = mapper(Employee, pjoin, polymorphic_on=pjoin.c.type) mapper( Manager, managers_table, inherits=employee_mapper, concrete=True, polymorphic_identity="manager", ) engineer_mapper = mapper( Engineer, engineers_table, with_polymorphic=("*", pjoin2), polymorphic_on=pjoin2.c.type, inherits=employee_mapper, concrete=True, polymorphic_identity="engineer", ) mapper( Hacker, hackers_table, inherits=engineer_mapper, concrete=True, polymorphic_identity="hacker", ) session = create_session() tom = Manager("Tom", "knows how to manage things") assert_raises_message( AttributeError, "does not implement attribute .?'type' at the instance level.", setattr, tom, "type", "sometype", ) jerry = Engineer("Jerry", "knows how to program") hacker = Hacker("Kurt", "Badass", "knows how to hack") assert_raises_message( AttributeError, "does not implement attribute .?'type' at the instance level.", setattr, hacker, "type", "sometype", ) session.add_all((tom, jerry, hacker)) session.flush() # ensure "readonly" on save logic didn't pollute the # expired_attributes collection assert ("nickname" not in attributes.instance_state(jerry).expired_attributes) assert ("name" not in attributes.instance_state(jerry).expired_attributes) assert ("name" not in attributes.instance_state(hacker).expired_attributes) assert ("nickname" not in attributes.instance_state(hacker).expired_attributes) def go(): eq_(jerry.name, "Jerry") eq_(hacker.nickname, "Badass") self.assert_sql_count(testing.db, go, 0) session.expunge_all() assert (repr( session.query(Employee).filter(Employee.name == "Tom").one()) == "Manager Tom knows how to manage things") assert (repr( session.query(Manager).filter(Manager.name == "Tom").one()) == "Manager Tom knows how to manage things") assert set([repr(x) for x in session.query(Employee).all()]) == set([ "Engineer Jerry knows how to program", "Manager Tom knows how to manage things", "Hacker Kurt 'Badass' knows how to hack", ]) assert set([repr(x) for x in session.query(Manager).all() ]) == set(["Manager Tom knows how to manage things"]) assert set([repr(x) for x in session.query(Engineer).all()]) == set([ "Engineer Jerry knows how to program", "Hacker Kurt 'Badass' knows how to hack", ]) assert set([repr(x) for x in session.query(Hacker).all() ]) == set(["Hacker Kurt 'Badass' knows how to hack"])
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 manager = register_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) if base is object: assert Foo not in ( instrumentation._instrumentation_factory._state_finders) else: assert Foo in ( instrumentation._instrumentation_factory._state_finders) f = Foo() attributes.instance_state(f)._expire(attributes.instance_dict(f), set()) eq_(f.a, "this is a") eq_(f.b, 12) f.a = "this is some new a" attributes.instance_state(f)._expire(attributes.instance_dict(f), set()) eq_(f.a, "this is a") eq_(f.b, 12) attributes.instance_state(f)._expire(attributes.instance_dict(f), set()) 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.instance_dict(f), set()) 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_history(self): for base in (object, MyBaseClass, MyClass): class Foo(base): pass class Bar(base): pass register_class(Foo) 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_state_history(attributes.instance_state(f1), "name"), (["f1"], (), ()), ) b1 = Bar() b1.name = "b1" f1.bars.append(b1) eq_( attributes.get_state_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_state_history(attributes.instance_state(f1), "name"), ((), ["f1"], ()), ) eq_( attributes.get_state_history(attributes.instance_state(f1), "bars"), ((), [b1], ()), ) f1.name = "f1mod" b2 = Bar() b2.name = "b2" f1.bars.append(b2) eq_( attributes.get_state_history(attributes.instance_state(f1), "name"), (["f1mod"], (), ["f1"]), ) eq_( attributes.get_state_history(attributes.instance_state(f1), "bars"), ([b2], [b1], []), ) f1.bars.remove(b1) eq_( attributes.get_state_history(attributes.instance_state(f1), "bars"), ([b2], [], [b1]), )