Source code for diffpy.srfit.util.observable

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
#                             michael a.g. aïvázis
#                                  orthologue
#                      (c) 1998-2009  all rights reserved
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Derived from pyre-1.0/packages/pyre/patterns/Observable.py
# See pyre-1.0 for full copyright and license information

__all__ = ["Observable"]


from diffpy.srfit.util.weakrefcallable import weak_ref
from diffpy.utils._deprecator import build_deprecation_message, deprecated

observable_base = "diffpy.srfit.util.observable.Observable"
removal_version = "4.0.0"
addObserver_dep_msg = build_deprecation_message(
    observable_base, "addObserver", "add_observer", removal_version
)
removeObserver_dep_msg = build_deprecation_message(
    observable_base, "removeObserver", "remove_observer", removal_version
)
hasObserver_dep_msg = build_deprecation_message(
    observable_base, "hasObserver", "has_observer", removal_version
)


[docs] class Observable(object): """Provide notification support for classes that maintain dynamic associations with multiple clients. Observers, i.e. clients of the observable, register event handlers that will be invoked to notify them whenever something interesting happens to the observable. The nature of what is being observed is defined by Observable descendants and their managers. For example, instances of pyre.calc.Node are observable by other nodes whose value depends on them so that the dependents can be notified about value changes and forced to recompute their own value. The event handlers are callables that take a tuple starting with the observable instance as their single argument. Register them with ``add_observer``, remove them with ``remove_observer``, and invoke them all with ``notify``. """
[docs] def notify(self, other=()): """Notify all observers. Parameters ---------- other : tuple, optional The extra objects passed to each observer after this observable. Default is an empty tuple. """ # build a list before notification, just in case the observer's # callback behavior involves removing itself from our callback set semaphores = (self,) + other for callable in tuple(self._observers): callable(semaphores) return
# callback management
[docs] def add_observer(self, callable): """Add a callable to the set of observers. Bound methods are held by weak reference, and are removed automatically once their object is deleted. Parameters ---------- callable : callable The observer to call when this observable notifies. """ f = weak_ref(callable, fallback=_fb_remove_observer) self._observers.add(f) return
[docs] def remove_observer(self, callable): """Remove a callable from the set of observers. Parameters ---------- callable : callable The observer to remove. Raises ------ KeyError If ``callable`` is not an observer of this observable. """ f = weak_ref(callable) self._observers.remove(f) return
[docs] def has_observer(self, callable): """Check whether a callable is in the set of observers. Parameters ---------- callable : callable The observer to look for. Returns ------- bool The flag that is True if ``callable`` is an observer. """ f = weak_ref(callable) rv = f in self._observers return rv
@deprecated(addObserver_dep_msg) def addObserver(self, callable): """This function has been deprecated and will be removed in version 4.0.0. Please use diffpy.srfit.util.observable.Observable.add_observer instead. """ return self.add_observer(callable) @deprecated(removeObserver_dep_msg) def removeObserver(self, callable): """This function has been deprecated and will be removed in version 4.0.0. Please use diffpy.srfit.util.observable.Observable.remove_observer instead. """ return self.remove_observer(callable) @deprecated(hasObserver_dep_msg) def hasObserver(self, callable): """This function has been deprecated and will be removed in version 4.0.0. Please use diffpy.srfit.util.observable.Observable.has_observer instead. """ return self.has_observer(callable) # meta methods def __init__(self, **kwds): super(Observable, self).__init__(**kwds) self._observers = set() return
# end of class Observable # Local helpers -------------------------------------------------------------- def _fb_remove_observer(fobs, semaphores): # Remove WeakBoundMethod `fobs` from the observers of notifying object. # This is called from Observable.notify when the WeakBoundMethod # associated object dies. observable = semaphores[0] observable.remove_observer(fobs) return # end of file