def __init__(self, reference): self.reference = reference self._id = None self._properties = StrictDict() self.currentCommand = None
class EngineFromReference(object): """Adapt a `RemoteReference` to an `IEngineBase` implementing object. When an engine connects to a controller, it calls the `register_engine` method of the controller and passes the controller a `RemoteReference` to itself. This class is used to adapt this `RemoteReference` to an object that implements the full `IEngineBase` interface. See the documentation of `IEngineBase` for details on the methods. """ implements(IEngineBase) def __init__(self, reference): self.reference = reference self._id = None self._properties = StrictDict() self.currentCommand = None def callRemote(self, *args, **kwargs): try: return self.reference.callRemote(*args, **kwargs) except DeadReferenceError: self.notifier() self.stopNotifying(self.notifier) return defer.fail() def get_id(self): """Return the Engines id.""" return self._id def set_id(self, id): """Set the Engines id.""" self._id = id return self.callRemote('set_id', id) id = property(get_id, set_id) def syncProperties(self, r): try: psync, result = r except (ValueError, TypeError): return r else: if psync: log.msg("sync properties") pick = self.checkReturnForFailure(psync) if isinstance(pick, failure.Failure): self.properties = pick return pick else: self.properties = pickle.loads(pick) return result def _set_properties(self, dikt): self._properties.clear() self._properties.update(dikt) def _get_properties(self): if isinstance(self._properties, failure.Failure): self._properties.raiseException() return self._properties properties = property(_get_properties, _set_properties) #--------------------------------------------------------------------------- # Methods from IEngine #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # execute #--------------------------------------------------------------------------- def execute(self, lines): # self._needProperties = True d = self.callRemote('execute', lines) d.addCallback(self.syncProperties) return d.addCallback(self.checkReturnForFailure) #--------------------------------------------------------------------------- # push #--------------------------------------------------------------------------- def push(self, namespace): try: package = pickle.dumps(namespace, 2) except: return defer.fail(failure.Failure()) else: if isinstance(package, failure.Failure): return defer.fail(package) else: d = self.callRemote('push', package) return d.addCallback(self.checkReturnForFailure) #--------------------------------------------------------------------------- # pull #--------------------------------------------------------------------------- def pull(self, keys): d = self.callRemote('pull', keys) d.addCallback(self.checkReturnForFailure) d.addCallback(pickle.loads) return d #--------------------------------------------------------------------------- # push/pull_function #--------------------------------------------------------------------------- def push_function(self, namespace): try: package = pickle.dumps(canDict(namespace), 2) except: return defer.fail(failure.Failure()) else: if isinstance(package, failure.Failure): return defer.fail(package) else: d = self.callRemote('push_function', package) return d.addCallback(self.checkReturnForFailure) def pull_function(self, keys): d = self.callRemote('pull_function', keys) d.addCallback(self.checkReturnForFailure) d.addCallback(pickle.loads) # The usage of globals() here is an attempt to bind any pickled functions # to the globals of this module. What we really want is to have it bound # to the globals of the callers module. This will require walking the # stack. BG 10/3/07. if len(keys)==1: d.addCallback(uncan, globals()) elif len(keys)>1: d.addCallback(uncanSequence, globals()) return d #--------------------------------------------------------------------------- # Other methods #--------------------------------------------------------------------------- def get_result(self, i=None): return self.callRemote('get_result', i).addCallback(self.checkReturnForFailure) def reset(self): self._refreshProperties = True d = self.callRemote('reset') d.addCallback(self.syncProperties) return d.addCallback(self.checkReturnForFailure) def kill(self): #this will raise pb.PBConnectionLost on success d = self.callRemote('kill') d.addCallback(self.syncProperties) d.addCallback(self.checkReturnForFailure) d.addErrback(self.killBack) return d def killBack(self, f): log.msg('filling engine: %s' % f) return None def keys(self): return self.callRemote('keys').addCallback(self.checkReturnForFailure) #--------------------------------------------------------------------------- # Properties methods #--------------------------------------------------------------------------- def set_properties(self, properties): try: package = pickle.dumps(properties, 2) except: return defer.fail(failure.Failure()) else: if isinstance(package, failure.Failure): return defer.fail(package) else: d = self.callRemote('set_properties', package) return d.addCallback(self.checkReturnForFailure) return d def get_properties(self, keys=None): d = self.callRemote('get_properties', keys) d.addCallback(self.checkReturnForFailure) d.addCallback(pickle.loads) return d def has_properties(self, keys): d = self.callRemote('has_properties', keys) d.addCallback(self.checkReturnForFailure) d.addCallback(pickle.loads) return d def del_properties(self, keys): d = self.callRemote('del_properties', keys) d.addCallback(self.checkReturnForFailure) # d.addCallback(pickle.loads) return d def clear_properties(self): d = self.callRemote('clear_properties') d.addCallback(self.checkReturnForFailure) return d #--------------------------------------------------------------------------- # push/pull_serialized #--------------------------------------------------------------------------- def push_serialized(self, namespace): """Older version of pushSerialize.""" try: package = pickle.dumps(namespace, 2) except: return defer.fail(failure.Failure()) else: if isinstance(package, failure.Failure): return defer.fail(package) else: d = self.callRemote('push_serialized', package) return d.addCallback(self.checkReturnForFailure) def pull_serialized(self, keys): d = self.callRemote('pull_serialized', keys) d.addCallback(self.checkReturnForFailure) d.addCallback(pickle.loads) return d #--------------------------------------------------------------------------- # Misc #--------------------------------------------------------------------------- def checkReturnForFailure(self, r): """See if a returned value is a pickled Failure object. To distinguish between general pickled objects and pickled Failures, the other side should prepend the string FAILURE: to any pickled Failure. """ return unpackageFailure(r)