--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 4069
+ :versions: 1.2.0b3
+
+ Fixed bug in :meth:`.Session.merge` following along similar lines as that
+ of :ticket:`4030`, where an internal check for a target object in
+ the identity map could lead to an error if it were to be garbage collected
+ immediately before the merge routine actually retrieves the object.
\ No newline at end of file
key_is_persistent = True
if key in self.identity_map:
- merged = self.identity_map[key]
- elif key_is_persistent and key in _resolve_conflict_map:
- merged = _resolve_conflict_map[key]
-
- elif not load:
- if state.modified:
- raise sa_exc.InvalidRequestError(
- "merge() with load=False option does not support "
- "objects marked as 'dirty'. flush() all changes on "
- "mapped instances before merging with load=False.")
- merged = mapper.class_manager.new_instance()
- merged_state = attributes.instance_state(merged)
- merged_state.key = key
- self._update_impl(merged_state)
- new_instance = True
-
- elif key_is_persistent:
- merged = self.query(mapper.class_).get(key[1])
+ try:
+ merged = self.identity_map[key]
+ except KeyError:
+ # object was GC'ed right as we checked for it
+ merged = None
else:
merged = None
+ if merged is None:
+ if key_is_persistent and key in _resolve_conflict_map:
+ merged = _resolve_conflict_map[key]
+
+ elif not load:
+ if state.modified:
+ raise sa_exc.InvalidRequestError(
+ "merge() with load=False option does not support "
+ "objects marked as 'dirty'. flush() all changes on "
+ "mapped instances before merging with load=False.")
+ merged = mapper.class_manager.new_instance()
+ merged_state = attributes.instance_state(merged)
+ merged_state.key = key
+ self._update_impl(merged_state)
+ new_instance = True
+
+ elif key_is_persistent:
+ merged = self.query(mapper.class_).get(key[1])
+
if merged is None:
merged = mapper.class_manager.new_instance()
merged_state = attributes.instance_state(merged)