<s> """<STR_LIT>""" <EOL> import re <EOL> import sys <EOL> import time <EOL> import inspect <EOL> class Signal : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , fun ) : <EOL> self . _fun = fun <EOL> self . _value = None <EOL> self . _dirty = True <EOL> self . _dependers = [ ] <EOL> def __call__ ( self , * args ) : <EOL> if self . _dirty : <EOL> self . _value = self . _fun ( * args ) <EOL> self . _dirty = False <EOL> return self . _value <EOL> def set_dirty ( self ) : <EOL> self . _dirty = True <EOL> for dep in self . _dependers : <EOL> dep . set_dirty ( ) <EOL> dep ( ) <EOL> class Input ( Signal ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self ) : <EOL> Signal . __init__ ( self , lambda x = None : None ) <EOL> def set ( self , value ) : <EOL> self . _value = value <EOL> self . set_dirty ( ) <EOL> class Output ( Signal ) : <EOL> pass <EOL> def check_deps ( fun , locals , globals ) : <EOL> """<STR_LIT>""" <EOL> s = inspect . getsource ( fun . _fun ) <EOL> matches = re . findall ( r'<STR_LIT>' , s ) <EOL> fun . _nmatches = <NUM_LIT:0> <EOL> for match in matches : <EOL> ob = locals . get ( match [ <NUM_LIT:0> ] , globals . get ( match [ <NUM_LIT:0> ] , None ) ) <EOL> if ob is None : <EOL> print ( '<STR_LIT>' % match [ <NUM_LIT:0> ] ) <EOL> else : <EOL> ob . _bind_signal ( match [ <NUM_LIT:1> ] , fun ) <EOL> fun . _nmatches += <NUM_LIT:1> <EOL> if fun . _nmatches : <EOL> matches = re . findall ( r'<STR_LIT>' , s ) <EOL> for match in matches : <EOL> ob = locals . get ( match [ <NUM_LIT:0> ] , globals . get ( match [ <NUM_LIT:0> ] , None ) ) <EOL> if isinstance ( ob , Signal ) : <EOL> ob . _dependers . append ( fun ) <EOL> fun . _deps_checked = len ( matches ) <EOL> def react ( fun ) : <EOL> """<STR_LIT>""" <EOL> _frame = sys . _getframe ( <NUM_LIT:1> ) <EOL> if not isinstance ( fun , Signal ) : <EOL> fun = Signal ( fun ) <EOL> check_deps ( fun , _frame . f_locals , _frame . f_globals ) <EOL> if fun . _nmatches : <EOL> return fun <EOL> else : <EOL> return fun . _fun <EOL> class Reactive : <EOL> """<STR_LIT>""" <EOL> SIGNALS = [ ] <EOL> def __init__ ( self ) : <EOL> self . _signals = { } <EOL> self . _downstream = { } <EOL> for name , val in self . SIGNALS : <EOL> self . _signals [ name ] = val <EOL> for name in dir ( self . __class__ ) : <EOL> cls_ob = getattr ( self . __class__ , name ) <EOL> if hasattr ( cls_ob , '<STR_LIT>' ) : <EOL> fun = getattr ( self , name ) <EOL> react ( fun ) <EOL> def _emit_signal ( self , name , value ) : <EOL> self . _signals [ name ] = value <EOL> for f in self . _downstream . get ( name , ( ) ) : <EOL> f . set_dirty ( ) <EOL> f ( ) <EOL> def _bind_signal ( self , name , fun ) : <EOL> funcs = self . _downstream . setdefault ( name , [ ] ) <EOL> if fun not in funcs : <EOL> funcs . append ( fun ) <EOL> def bind_signals ( self , * args ) : <EOL> def bind ( fun ) : <EOL> if not isinstance ( fun , Signal ) : <EOL> fun = Signal ( fun ) <EOL> for name in names : <EOL> funcs = self . _downstream . setdefault ( name , [ ] ) <EOL> if fun not in funcs : <EOL> funcs . append ( fun ) <EOL> return fun <EOL> fun = None <EOL> names = [ ] <EOL> for arg in args : <EOL> if callable ( arg ) : <EOL> fun = arg <EOL> else : <EOL> names . append ( arg ) <EOL> print ( '<STR_LIT>' , names ) <EOL> if fun is None : <EOL> return bind <EOL> else : <EOL> return bin ( fun ) <EOL> def get_signal ( self , name ) : <EOL> if False : <EOL> s = inspect . stack ( ) <EOL> caller = s [ <NUM_LIT:1> ] <EOL> print ( caller [ <NUM_LIT:0> ] . f_locals . keys ( ) ) <EOL> print ( caller [ <NUM_LIT:0> ] . f_globals . keys ( ) ) <EOL> id = caller [ <NUM_LIT:1> ] , caller [ <NUM_LIT:2> ] , caller [ <NUM_LIT:3> ] <EOL> self . caller = caller <EOL> self . caller2 = sys . _getframe ( <NUM_LIT:1> ) <EOL> fun = caller [ <NUM_LIT:0> ] . f_globals [ id [ - <NUM_LIT:1> ] ] <EOL> print ( id , fun ) <EOL> self . _bind_signal ( name , fun ) <EOL> return self . _signals [ name ] <EOL> def set_output ( self , name , value ) : <EOL> f = getattr ( self , '<STR_LIT>' + name ) <EOL> f ( value ) <EOL> print ( '<STR_LIT>' ) <EOL> class Widget ( Reactive ) : <EOL> SIGNALS = [ ( '<STR_LIT>' , <NUM_LIT:0> ) , ( '<STR_LIT>' , <NUM_LIT:0> ) ] <EOL> def manual_slider1 ( self , v ) : <EOL> """<STR_LIT>""" <EOL> self . _emit_signal ( '<STR_LIT>' , v ) <EOL> def manual_slider2 ( self , v ) : <EOL> self . _emit_signal ( '<STR_LIT>' , v ) <EOL> def on_show ( self , val ) : <EOL> print ( '<STR_LIT>' , val ) <EOL> class Widget1 ( Widget ) : <EOL> @ react <EOL> def bla1 ( self ) : <EOL> x = self . get_signal ( '<STR_LIT>' ) * <NUM_LIT:3> <EOL> self . set_output ( '<STR_LIT>' , x ) <EOL> w = Widget1 ( ) <EOL> @ react <EOL> def something_that_takes_long ( ) : <EOL> print ( '<STR_LIT>' ) <EOL> time . sleep ( <NUM_LIT:1> ) <EOL> return w . get_signal ( '<STR_LIT>' ) * <NUM_LIT:2> <EOL> @ react <EOL> def bla ( ) : <EOL> x = something_that_takes_long ( ) <EOL> x += w . get_signal ( '<STR_LIT>' ) <EOL> w . set_output ( '<STR_LIT>' , x - <NUM_LIT:1> ) <EOL> print ( '<STR_LIT>' ) <EOL> class Widget2 ( Widget ) : <EOL> def on_slider1_change ( self ) : <EOL> x = self . get_signal ( '<STR_LIT>' ) * <NUM_LIT:3> <EOL> self . set_output ( '<STR_LIT>' , x ) <EOL> w2 = Widget2 ( ) <EOL> @ w2 . bind_signals ( '<STR_LIT>' ) <EOL> def something_that_takes_long ( ) : <EOL> print ( '<STR_LIT>' ) <EOL> time . sleep ( <NUM_LIT:1> ) <EOL> return w2 . get_signal ( '<STR_LIT>' ) * <NUM_LIT:2> <EOL> @ w2 . bind_signals ( '<STR_LIT>' ) <EOL> def bla ( ) : <EOL> x = something_that_takes_long ( ) <EOL> x += w2 . get_signal ( '<STR_LIT>' ) <EOL> w2 . set_output ( '<STR_LIT>' , x - <NUM_LIT:1> ) <EOL> print ( '<STR_LIT>' ) <EOL> class Temp2 ( Reactive ) : <EOL> """<STR_LIT>""" <EOL> SIGNALS = [ ( '<STR_LIT:C>' , <NUM_LIT:0> ) , ( '<STR_LIT:F>' , <NUM_LIT:32> ) ] <EOL> t2 = Temp2 ( ) <EOL> self = t2 <EOL> @ t2 . bind_signals ( '<STR_LIT:F>' ) <EOL> def _c2f ( ) : <EOL> self . _signals [ '<STR_LIT:C>' ] = ( self . get_signal ( '<STR_LIT:F>' ) - <NUM_LIT:32> ) / <NUM_LIT> <EOL> @ t2 . bind_signals ( '<STR_LIT:C>' ) <EOL> def _f2c ( ) : <EOL> self . _signals [ '<STR_LIT:F>' ] = self . get_signal ( '<STR_LIT:C>' ) * <NUM_LIT> + <NUM_LIT:32> <EOL> @ t2 . bind_signals ( '<STR_LIT:C>' , '<STR_LIT:F>' ) <EOL> def _show ( ) : <EOL> print ( '<STR_LIT>' , self . get_signal ( '<STR_LIT:C>' ) ) <EOL> print ( '<STR_LIT>' , self . get_signal ( '<STR_LIT:F>' ) ) </s>
