def defer_to_thread(f, *args, **kwargs): """ Run a function in a thread and return the result as a Deferred. @param f: The function to call. @param *args: positional arguments to pass to f. @param **kwargs: keyword arguments to pass to f. @return: A Deferred which fires a callback with the result of f, or an errback with a L{twisted.python.failure.Failure} if f throws an exception. """ def run_thread(df, func, *f_args, **f_kwargs): try: logger.debug("Calling function {0} in thread.".format(func)) result = func(*f_args, **f_kwargs) logger.debug( "Thread deferred function returned {0}".format(result)) df.callback(result) except Exception as e: logger.error("Got error in thread: {0}".format(e)) df.errback(e) logger.info("Deferring function {0} to thread.".format(f)) if "canceller" in kwargs: d = defer.Deferred(kwargs["canceller"]) else: d = defer.Deferred() rt_args = (d, f) + args t = threading.Thread(target=run_thread, args=rt_args, kwargs=kwargs) t.start() return d
def start(self, interval, now=True): """ Start running function every interval seconds. @param interval: The number of seconds between calls. May be less than one. Precision will depend on the underlying platform, the available hardware, and the load on the system. @param now: If True, run this call right now. Otherwise, wait until the interval has elapsed before beginning. @return: A Deferred whose callback will be invoked with C{self} when C{self.stop} is called, or whose errback will be invoked when the function raises an exception or returned a deferred that has its errback invoked. """ if self.running is True: self.stop() self.logger.debug( "Starting looping call at interval {0} s".format(interval)) if interval < 0: raise ValueError("interval must be >= 0") self.running = True # Loop might fail to start and then self._deferred will be cleared. # This why the local C{deferred} variable is used. deferred = self._deferred = defer.Deferred() self.starttime = time.time() self.interval = interval self._runAtStart = now if now: self() else: self._schedule_from(self.starttime) return deferred
def defer_to_queue(self, f, *args, **kwargs): print("Defer to queue: {0}. Args: {1}, kwargs: {2}".format(f, args, kwargs)) d = defer.Deferred(canceller=self.cancel_queue_cmd_from_deferred) cmd = d d.addCallback(self.queue_cb, f, *args, **kwargs) with self.lock: self.q.put(cmd) return d
def write_parameter(self, name, value, process_now=True, readback=True): """ Write a single named parameter to the Patara. If readback is True the same parameter is scheduled to be read after the write. The retured deferred fires when the result is ready. :param name: Name of the parameter according the eDrive User Manual :param value: Value to write :param process_now: True if the queue should be processes immediately :param readback: True if the value should be read back from the Patara :return: Deferred that fires when the result is ready """ p = self.get_parameter(name) if p is None: err = "Name {0} not in parameter dictionary".format(name) self.logger.error(err) d = defer.Deferred() fail = failure.Failure(AttributeError(err)) d.errback(fail) return d addr = p.get_address() func = p.get_function_code() (factor, offset) = p.get_conversion() w_val = np.uint16((value - offset) / factor) self.logger.info( "Writing to {0}. Addr: {1}, func {2}, value {3}".format( name, addr, func, w_val)) if func == 1: f = self.client.write_coil elif func == 3: f = self.client.write_register else: err = "Wrong function code {0}, should be 1, or 3".format(func) self.logger.error(err) d = defer.Deferred() fail = failure.Failure(AttributeError(err)) d.errback(fail) return d d = self.defer_to_queue(f, addr, w_val, unit=self.slave_id) # d = defer.Deferred() d.addErrback(self.client_error) if readback is True: d = self.read_parameter(name, process_now) if process_now is True: self.process_queue() return d
def add_task(self, f, *args, **kwargs): d = defer.Deferred() self.logger.debug("Putting task in queue. Args: {0}".format(args)) with self.id_lock: id = self.next_process_id self.next_process_id += 1 self.in_queue.put((f, args, kwargs, id)) self.deferred_dict[id] = d return d
def read_parameter(self, name, process_now=True): """ Read a single named parameter from the Patara and store the result in the parameter dictionary. The retured deferred fires when the result is ready. :param name: Name of the parameter according the eDrive User Manual :param process_now: True if the queue should be processes immediately :return: Deferred that fires when the result is ready """ p = self.get_parameter(name) if p is None: err = "Name {0} not in parameter dictionary".format(name) self.logger.error(err) d = defer.Deferred() fail = failure.Failure(AttributeError(err)) d.errback(fail) return d addr = p.get_address() func = p.get_function_code() self.logger.debug("Reading {0}. Addr: {1}, func {2}".format( name, addr, func)) if func == 1: f = self.client.read_coils elif func == 2: f = self.client.read_discrete_inputs elif func == 3: f = self.client.read_holding_registers elif func == 4: f = self.client.read_input_registers else: err = "Wrong function code {0}, should be 1, 2, 3, or 4".format( func) self.logger.error(err) d = defer.Deferred() fail = failure.Failure(AttributeError(err)) d.errback(fail) return d d = self.defer_to_queue(f, addr, 1, unit=self.slave_id) d.addCallback(self.process_parameters, min_addr=addr) d.addErrback(self.client_error) if process_now is True: self.process_queue() return d
def defer_later(delay, delayed_callable, *a, **kw): # logger.info("Calling {0} in {1} seconds".format(delayed_callable, delay)) def defer_later_cancel(deferred): delayed_call.cancel() d = defer.Deferred(defer_later_cancel) d.addCallback(lambda ignored: delayed_callable(*a, **kw)) delayed_call = threading.Timer(delay, d.callback, [None]) delayed_call.start() return d
def cb(result): if self.running: self._schedule_from(time.time()) new_loop_deferred = defer.Deferred() for callback in self.loop_deferred.callbacks: new_loop_deferred.callbacks.append(callback) self.loop_deferred.callback(result) self.loop_deferred = new_loop_deferred else: df, self._deferred = self._deferred, None df.callback(self)
def get_attribute(self, name): if name in self.attribute_dict: self.logger.debug( "Attribute {0} already read. Retrieve from dictionary.".format( name)) d = defer.Deferred() d.callback(self.attribute_dict[name]) else: self.logger.debug( "Attribute {0} not in dictionary, retrieve it from device". format(name)) d = self.buildProtocol("read", name) return d
def deferred_from_future(future): d = defer.Deferred() def callback(future): e = future.exception() if e: d.errback(e) return d.callback(future.result()) future.add_done_callback(callback) return d
def __init__(self, loop_callable, *args, **kw): self.f = loop_callable self.args = args self.kw = kw self.running = False self.interval = 0.0 self.starttime = None self._deferred = None self._runAtStart = False self.call = None self.loop_deferred = defer.Deferred() self.logger = logging.getLogger("TangoTwisted.LoopingCall") self.logger.setLevel(logging.WARNING)
def defer_to_queue(self, f, *args, **kwargs): self.logger.debug( "Deferring {0} with args {1}, kwargs {2} to queue".format( f, args, kwargs)) d = defer.Deferred(canceller=self.cancel_queue_cmd_from_deferred) # cmd = (d, f, args, kwargs) # cmd = d # d.addCallback(f, args, kwargs) # with self.lock: # self.command_queue.put(cmd) # return d # d.addCallback(self.queue_cb, f, *args, **kwargs) with self.lock: self.command_queue.put(d) return d
def defer_to_pool(pool, f, *args, **kwargs): df = defer.Deferred() def pool_callback(result): if isinstance(result, Exception): df.errback(result) else: df.callback(result) logger.info("Deferring function {0} to process pool.".format(f)) args_wrapper = (f, ) + args pool.apply_async(f_wrapper, args=args_wrapper, kwds=kwargs, callback=pool_callback) # pool.apply_async(f, args=args, kwds=kwargs, callback=pool_callback) return df
def start(self, interval, timeout=None): if self.running is True: self.stop() self.logger.debug("Starting checking condition {0}".format( self.condition)) if interval < 0: raise ValueError("interval must be >= 0") self.running = True # Loop might fail to start and then self._deferred will be cleared. # This why the local C{deferred} variable is used. deferred = self._deferred = defer.Deferred() if timeout is not None: self.clock = ClockReactorless() deferred.addTimeout(timeout, self.clock) deferred.addErrback(self.cond_error) self.starttime = time.time() self.interval = interval self._run_callable() return deferred
def defer_to_thread(f, *args, **kwargs): """ Run a function in a thread and return the result as a Deferred. @param f: The function to call. @param *args: positional arguments to pass to f. @param **kwargs: keyword arguments to pass to f. @return: A Deferred which fires a callback with the result of f, or an errback with a L{twisted.python.failure.Failure} if f throws an exception. """ def run_thread(df, func, *f_args, **f_kwargs): print("Run thread {0}. Args: {1}, kwargs: {2}".format(func, f_args, f_kwargs)) try: result = func(*f_args, **f_kwargs) df.callback(result) except Exception as e: df.errback(e) print("Defer to thread: {0}. Args: {1}, kwargs: {2}".format(f, args, kwargs)) d = defer.Deferred() rt_args = (d, f) + args t = threading.Thread(target=run_thread, args=rt_args, kwargs=kwargs) t.start() return d
def check_attribute(self): """ Check an attribute to see if it reaches a target value. Returns a deferred for the result of the check. Upon calling the function the target is written to the attribute if the "write" parameter is True. Then reading the attribute is polled with the period "period" for a maximum time of "timeout". If the read value is within tolerance, the callback deferred is fired. If the read value is outside tolerance after "timeout" time, the errback is fired. The maximum time to check is "timeout" :param attr_name: Tango name of the attribute to check, e.g. "position" :param dev_name: Tango device name to use, e.g. "gunlaser/motors/zaber01" :param target_value: Attribute value to wait for :param period: Polling period when checking the value :param timeout: Time to wait for the attribute to reach target value :param tolerance: Absolute tolerance for the value to be accepted :param write: Set to True if the target value should be written initially :return: Deferred that will fire depending on the result of the check """ self.logger.info("Entering check_attribute") self.d = defer.Deferred() try: write = self.kw["write"] except KeyError: write = True try: self._check_timeout = self.kw["timeout"] except KeyError: self.logger.debug("No timeout specified, using 1.0 s") self._check_timeout = 1.0 try: self._check_tolerance = self.kw["tolerance"] except KeyError: self._check_tolerance = None self.logger.debug("No tolerance specified, using None") try: self._check_period = self.kw["period"] except KeyError: self._check_period = 0.3 self.logger.debug("No period specified, using 0.3 s") try: self._check_target_value = self.kw["target_value"] except KeyError: self._check_target_value = None self.logger.error("No target value specified") self.d.errback("Target value required") return self.d self._check_starttime = time.time() self._check_lastreadtime = self._check_starttime self._check_timeout_deferred = defer_later( self._check_timeout, self.d.errback, RuntimeError("Check {0} timeout".format(self.name))) if write is True: self.logger.debug("Issuing initial write") dw = deferred_from_future( self.factory.device.write_attribute(self.name, self._check_target_value, wait=False)) # Add a callback that starts the reading after write completes dw.addCallbacks(self._check_do_read, self._check_fail) else: self.logger.debug("Issuing initial read") dw = deferred_from_future( self.factory.device.read_attribute(self.name, wait=False)) dw.addCallbacks(self._check_read_done, self._check_fail) # Return the deferred that will fire with the result of the check return self.d