those configured on the mapper. False will make it
as though order_by() was never called, while
None is an active setting.
+
+ - An instance which is moved to "transient", has
+ an incomplete or missing set of primary key
+ attributes, and contains expired attributes, will
+ raise an InvalidRequestError if an expired attribute
+ is accessed, instead of getting a recursion overflow.
+
+ - The make_transient() function is now in the generated
+ documentation.
+
+ - make_transient() removes all "loader" callables from
+ the state being made transient, removing any
+ "expired" state - all unloaded attributes reset back
+ to undefined, None/empty on access.
- sql
- The warning emitted by the Unicode and String types
if has_key:
identity_key = state.key
else:
+ # this codepath is rare - only valid when inside a flush, and the
+ # object is becoming persistent but hasn't yet been assigned an identity_key.
+ # check here to ensure we have the attrs we need.
+ pk_attrs = [mapper._get_col_to_prop(col).key for col in mapper.primary_key]
+ if state.expired_attributes.intersection(pk_attrs):
+ raise sa_exc.InvalidRequestError("Instance %s cannot be refreshed - it's not "
+ " persistent and does not "
+ "contain a full primary key." % state_str(state))
identity_key = mapper._identity_key_from_state(state)
if (_none_set.issubset(identity_key) and \
such that it's as though the object were newly constructed,
except retaining its values.
+ Attributes which were "expired" or deferred at the
+ instance level are reverted to undefined, and
+ will not trigger any loads.
+
"""
state = attributes.instance_state(instance)
s = _state_session(state)
if s:
s._expunge_state(state)
+
+ # remove expired state and
+ # deferred callables
+ state.callables.clear()
del state.key
assert 'name' not in u.__dict__
sess.add(u)
assert u.name == 'jack'
+
+ @testing.resolve_artifact_names
+ def test_no_instance_key_no_pk(self):
+ # same as test_no_instance_key, but the PK columns
+ # are absent. ensure an error is raised.
+ mapper(User, users)
+ sess = create_session()
+ u = sess.query(User).get(7)
+ sess.expire(u, attribute_names=['name', 'id'])
+ sess.expunge(u)
+ attributes.instance_state(u).key = None
+ assert 'name' not in u.__dict__
+ sess.add(u)
+ assert_raises(sa_exc.InvalidRequestError, getattr, u, 'name')
+
+
@testing.resolve_artifact_names
def test_expire_preserves_changes(self):
"""test that the expire load operation doesn't revert post-expire changes"""
sess.add(u1)
assert u1 in sess.new
+ # test expired attributes
+ # get unexpired
+ u1 = sess.query(User).first()
+ sess.expire(u1)
+ make_transient(u1)
+ assert u1.id is None
+ assert u1.name is None
+
+
@testing.resolve_artifact_names
def test_autoflush_expressions(self):
"""test that an expression which is dependent on object state is