def __init__(self, initval, readonly=False, setter=None, getter=None, max_discard=100, *args, **kwargs): """ readonly (bool): if True, value setter will raise an exception. It's still possible to change the value by calling _set() and then notify() setter (callable value -> value): function that will be called whenever the value has to be changed and returns the new actual value (which might be different from what was given). getter (callable value -> value): function that will be called whenever the value has to be read and returns the current actual value. max_discard (int): amount of updates that can be discarded in a row if a new one is already available. 0 to keep (notify) all the messages (dangerous if callback is slower than the generator). """ VigilantAttributeBase.__init__(self, initval, *args, **kwargs) self.readonly = readonly if setter is None: self._setter = WeakMethod(self.__default_setter) else: self._setter = WeakMethod(setter) # to avoid cycles if getter is not None: self._getter = WeakMethod(getter) # to avoid cycles else: self._getter = None # different from ._listeners for notify() to do different things self._remote_listeners = set() # any unique string works self._global_name = None # to be filled when registered self._ctx = None self.pipe = None self.debug = False # If True, this VA will print a call stack when its value is set self.max_discard = max_discard
def subscribe(self, listener): with self._lock: count_before = self._count_listeners() # add string to listeners if listener is string if isinstance(listener, basestring): self._remote_listeners.add(listener) else: assert callable(listener) self._listeners.add(WeakMethod(listener)) logging.debug("Listener %r subscribed, now %d subscribers on %s", listener, self._count_listeners(), self._global_name) if count_before == 0: try: self.start_generate() except Exception as ex: logging.error("Subscribing listener %r to the dataflow failed. %s", listener, ex) if isinstance(listener, basestring): # remove string from listeners self._remote_listeners.discard(listener) else: self._listeners.discard(WeakMethod(listener)) logging.debug("Listener %r unsubscribed, now %d subscribers on %s", listener, self._count_listeners(), self._global_name) raise
def subscribe(self, listener): """ Register a callback function to be called when the ActiveValue is listener (function): callback function which takes as arguments dataflow (this object) and data (the new data array) """ # TODO update rate argument to indicate how often we need an update? assert callable(listener) with self._lock: count_before = len(self._listeners) self._listeners.add(WeakMethod(listener)) logging.debug("Listener %r subscribed, now %d subscribers", listener, len(self._listeners)) if count_before == 0: try: self.start_generate() except Exception as ex: logging.error( "Subscribing listener %r to the dataflow failed. %s", listener, ex) self._listeners.discard(WeakMethod(listener)) logging.debug( "Listener %r unsubscribed, now %d subscribers", listener, len(self._listeners)) raise
def __init__(self, notifier, uri, max_discard, zmq_ctx): """ notifier (callable): method to call when a new array arrives uri (string): unique string to identify the connection max_discard (int) zmq_ctx (0MQ context): available 0MQ context to use """ threading.Thread.__init__(self, name="zmq for dataflow " + uri) self.daemon = True self.uri = uri self.max_discard = max_discard self._ctx = zmq_ctx # don't keep strong reference to notifier so that it can be garbage # collected normally and it will let us know then that we can stop self.w_notifier = WeakMethod(notifier) # create a zmq synchronised channel to receive _commands self._commands = zmq_ctx.socket(zmq.PAIR) self._commands.connect("inproc://" + uri) # create a zmq subscription to receive the data self._data = zmq_ctx.socket(zmq.SUB) # TODO find out if it does something and if it does, depend on max_discard # (for now, we just set it to 0, the default, to never discard messages) if hasattr(self._data, "rcvhwm"): # zmq v3+ self._data.rcvhwm = 0 else: # zmq v2 self._data.hwm = 0 self._data.connect("ipc://" + uri)
def unsubscribe(self, listener): with self._lock: count_before = len(self._listeners) self._listeners.discard(WeakMethod(listener)) count_after = len(self._listeners) logging.debug("Listener %r unsubscribed, now %d subscribers", listener, count_after) if count_before > 0 and count_after == 0: self.stop_generate()
def __init__(self, *args, **kwargs): """ notifier (callable): if present, will be called with the list itself whenever it's changed. """ if "notifier" in kwargs: notifier = kwargs.pop("notifier") self._notifier = WeakMethod(notifier) else: logging.debug("Creating notifying list without notifier") list.__init__(self, *args, **kwargs)
def unsubscribe(self, listener): with self._lock: count_before = self._count_listeners() if isinstance(listener, basestring): # remove string from listeners self._remote_listeners.discard(listener) else: self._listeners.discard(WeakMethod(listener)) count_after = self._count_listeners() logging.debug("Listener %r unsubscribed, now %d subscribers on %s", listener, count_after, self._global_name) if count_before > 0 and count_after == 0: self.stop_generate()
def subscribe(self, listener): with self._lock: count_before = self._count_listeners() # add string to listeners if listener is string if isinstance(listener, basestring): self._remote_listeners.add(listener) else: assert callable(listener) self._listeners.add(WeakMethod(listener)) logging.debug("Listener %r subscribed, now %d subscribers on %s", listener, self._count_listeners(), self._global_name) if count_before == 0: self.start_generate()
def subscribe(self, listener, init=False): """ Register a callback function to be called when the VigilantAttributeBase is changed listener (function): callback function which takes as argument val the new value init (boolean): if True calls the listener directly, to initialise it """ assert callable(listener) if isinstance(listener, types.BuiltinMethodType): self._listeners.add(listener) else: self._listeners.add(WeakMethod(listener)) if init: listener(self.value)
def subscribe(self, listener, init=False, **kwargs): """ Register a callback function to be called when the VigilantAttributeBase is changed listener (function): callback function which takes as argument val the new value init (boolean): if True calls the listener directly, to initialise it Additional keyword arguments can be provided. They will be passed to listener *ONLY ONCE* and only if `init` is True! One of the reasons for this, is that we cannot easily store the `kwargs` into the `_listeners` set, because `dicts` are not hashable. """ assert callable(listener) self._listeners.add(WeakMethod(listener)) if init: listener(self.value, **kwargs)
def __init__(self, notifier, uri, max_discard, zmq_ctx): """ notifier (callable): method to call when a new value arrives uri (string): unique string to identify the connection max_discard (int) zmq_ctx (0MQ context): available 0MQ context to use """ threading.Thread.__init__(self, name="zmq for VA " + uri) self.daemon = True self.uri = uri self.max_discard = max_discard self._ctx = zmq_ctx # don't keep strong reference to notifier so that it can be garbage # collected normally and it will let us know then that we can stop self.w_notifier = WeakMethod(notifier) # create a zmq synchronised channel to receive commands self._commands = zmq_ctx.socket(zmq.PAIR) self._commands.connect("inproc://" + uri) # create a zmq subscription to receive the data self.data = zmq_ctx.socket(zmq.SUB) self.data.connect("ipc://" + uri)
def unsubscribe(self, listener): self._listeners.discard(WeakMethod(listener))