This is a small observer library. There are many, but this one meets my particular needs:
- Straightforward encapsulation of Algorithms that run when input conditions are changed
- Variables can be blocked to suppress updates until inputs have stabilized
- Never worry about callback ordering
- Observer syntax should be readable
See esp:
>>> def printVar(name):
... def p(x):
... print "%s: %r"%(name,x)
... return pDefine a Variable:
>>> v1=Variable(3)Make a derived variable:
>>> v2= (v1+3)/5
>>> v2.observe(printVar("v2"))Watch as changes propagate to the derived variable
>>> v1.value=27
v2: 6It also works when combining two variables
>>> v3 = v2 * 2
>>> v3.observe(printVar("v3"))
>>> v1.value= 12
v2: 3
v3: 6Read on to see how to implement a custom Algorithm: a transformation from inputs to outputs that is executed asynchronously as inputs change
Observable exposes the special property value, which is implemented by get() and set(). It also implements observe()
>>> o=Observable(1)
>>> o.observe(printVar("o"))
>>> o.value=2
o: 2Variable is like Observable, but updates can be suppressed using the
blocked flag, which is also observable. This is the main building block of
the module: blocking is essential to have updates propagate correctly when
there are diamond-shaped Flows: v1->(v2,v3)->v4
>>> v=Variable()
>>> v.observe(printVar("v"))
>>> v.value=3
v: 3
>>> v.block()
>>> v.value=4
>>> v.value=5
>>> v.unblock()
v: 5Variables can track other variables unidirectionally
>>> source=Variable(2)
>>> v.track_variable(source)
v: 2
>>> source.value=7
v: 7Variables can be linked with other variables bidirectionally
>>> v_copy=Variable()
>>> v_copy.observe(printVar("v_copy"))
>>> linkVariables(v,v_copy)
v_copy: 7
>>> source.value="two places at once"
v: 'two places at once'
v_copy: 'two places at once'
>>> unlinkVariables(v,v_copy)Algorithm is a container for variables that connects inputs to outputs
>>> class Inverter(Algorithm):
... _inputs_=('input',)
... _outputs_=('output',)
... def update(self):
... self.output.value=not self.input.value
>>> i=Inverter(enabled=False)
>>> i.output.observe(printVar("inverted"))
>>> i.enabled.set(True)
inverted: True
>>> i.input.value=True
inverted: FalseThese modules can be connected together to form a flow graph. The idea is to
use the blocked flag to suppress processing until the parent data has stopped
flapping about. There is also an enable flag which is useful to stop your
algorithm from executing until the inputs are connected.
** Todo: ** I don't care about weak references for now. At some point I may add them, but ** Todo: ** Make block/unblock operations threadsafe