def flatten_instance(self, value, caps, freezing): self.check_capabilities(Capabilities.instance_values, value, caps, freezing) referenceable = getattr(value, "referenceable", True) if referenceable: deref = self._prepare(value) if deref is not None: return deref snapshot = value.snapshot() if self._source_ver is not None: # TODO: If external adapter is needed change this to a cast if IVersionAdapter.providedBy(value): adapter = IVersionAdapter(value) snapshot = adapter.adapt_version(snapshot, self._source_ver, self._target_ver) dump = self.flatten_value(snapshot, caps, freezing) if freezing: packer, data = self.pack_frozen_instance, [dump] else: packer, data = (self.pack_instance, [[self.pack_type_name, value.type_name], dump]) if referenceable: return self._preserve(value, packer, data) else: return packer, data
def flatten_instance(self, value, caps, freezing): self.check_capabilities(Capabilities.instance_values, value, caps, freezing) referenceable = getattr(value, "referenceable", True) if referenceable: deref = self._prepare(value) if deref is not None: return deref snapshot = value.snapshot() if IVersionAdapter.providedBy(value): source = self.get_source_ver(value, snapshot) target = self.get_target_ver(value, snapshot) if target is not None: if target != source: snapshot = value.adapt_version(snapshot, source, target) value.store_version(snapshot, target) dump = self.flatten_value(snapshot, caps, freezing) if freezing: packer, data = self.pack_frozen_instance, [dump] else: packer, data = (self.pack_instance, [[self.pack_type_name, value.type_name], dump]) if referenceable: return self._preserve(value, packer, data) else: return packer, data
def _adapt_snapshot(self, restorator, snapshot): if self._source_ver is not None: # TODO: If external adapter is needed change this to a cast if IVersionAdapter.providedBy(restorator): adapter = IVersionAdapter(restorator) snapshot = adapter.adapt_version(snapshot, self._source_ver, self._target_ver) return snapshot
def restore_instance(self, type_name, data, refid=None, restorator=None, instance=None): if restorator is None: restorator = self._lookup_restorator(type_name) if instance is None: # Prepare the instance for recovery instance = restorator.prepare() if instance is None: # Immutable type, we can't delay restoration snapshot = self.unpack_data(data) old_snapshot = copy.copy(snapshot) snapshot = self._adapt_snapshot(restorator, snapshot) instance = restorator.restore(snapshot) self._instances.append((None, instance, None, refid)) if old_snapshot != snapshot: self._migrated = True if IVersionAdapter.providedBy(instance): instance.set_migrated() return instance # Delay the instance restoration for later to handle circular refs return self.delayed_unpacking(instance, self._continue_restoring_instance, restorator, instance, data, refid)
def finish_unpacking(self): while self._pending: fun, args, kwargs = self._pending.pop(0) fun(*args, **kwargs) # Initialize delayed mutable instances in creation order for restorator, instance, snapshot, _refid in self._instances: if restorator is not None: # delayed mutable instances old_snapshot = copy.copy(snapshot) snapshot = self._adapt_snapshot(restorator, snapshot) instance.recover(snapshot) if old_snapshot != snapshot: self._migrated = True if IVersionAdapter.providedBy(instance): instance.set_migrated() # Calls the instances post restoration callback in reversed order # in an intent to reduce the possibilities of instances relying # on there references being fully restored when called. # This should not be relied on anyway. for _, instance, _, _ in reversed(self._instances): restored_fun = getattr(instance, "restored", None) if restored_fun is not None: restored_fun()
def convert(self, data): try: # Pre-convert the data if a convertor was specified converted = self.pre_convertion(data) # Unpack the first level of values unpacked = self.unpack_data(converted) # Continue unpacking level by level self.finish_unpacking() # Inform object that it has migrated if this is a case if (IVersionAdapter.providedBy(unpacked) and self._migrated): unpacked.set_migrated() # Should be finished by now return unpacked finally: # Reset the state to cleanup all references self.reset()
def migration_script(connection): log.info("script", "Running the migration script.") index = yield connection.query_view(view.DocumentByType, group_level=2, parse_result=False) try: for (type_name, version), count in index: restorator = serialization.lookup(type_name) if not restorator: log.error( 'script', "Failed to lookup the restorator for the " "type name: %s. There is %d objects like this in the" " database. They will not be migrated.", type_name, count) if (IVersionAdapter.providedBy(restorator) and ((version is None and restorator.version > 1) or (version is not None and version < restorator.version))): log.info('script', "I will migrate %d documents of the " "type: %s from version %s to %d", count, type_name, version, restorator.version) migrated = 0 while migrated < count: fetched = yield connection.query_view( view.DocumentByType, key=(type_name, version), limit=15, reduce=False, include_docs=True) migrated += len(fetched) if not fetched: break log.info("script", "Migrated %d documents of the type %s " "from %s version to %s", migrated, type_name, version, restorator.version) except Exception: error.handle_exception("script", None, "Failed running migration script") raise
def testAdaptation(self): self.assertTrue(IVersionAdapter.providedBy(A))