Changeset 86

Show
Ignore:
Timestamp:
03/01/08 19:45:59 (10 months ago)
Author:
jkyllo
Message:

Added NodeInputOutput? - a class that buffers input for later output (acts as both Input and Output).
Changed up Input and Output a little bit.
Changed PassthroughNode? to use NodeInputOutput?.
Added ConsolePrintNode? - a Node class that prints input to the console.
Added FuncOutput? - an Output class that provides a simple function for adding output.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/spike-20070613 tubes/tubes.py

    r83 r86  
    4040        return self.outputs 
    4141 
     42class NodeInputOutput(object): 
     43    """NodeInputOutput acts as an Input or an Output for a Node.  It buffers data that 
     44    is written to it so that it may later be read (in order).  It doesn't care 
     45    whether it is used as an Input or as an Output and really could be used as 
     46    either.""" 
     47    def __init__(self): 
     48        self.buffer = [] 
     49        self.nc = NotificationCenter() 
     50        self.source = None 
     51 
     52    def connect(self, output): 
     53        self.source = output 
     54        self.nc.addListener(output, 'DATA_READY', self.processInput) 
     55 
     56    def disconnect(self): 
     57        self.nc.removeListener(output, 'DATA_READY', self.processInput) 
     58        self.source = None 
     59 
     60    def processInput(self, node_output, signal): 
     61        if signal == 'DATA_READY': 
     62            self.write(node_output.read()) 
     63 
     64 
     65 
     66 
     67    ####  Node Output 
     68    def readyData(self): 
     69        return len(self.buffer) 
     70 
     71    def read(self, count=1): 
     72        #print '>>>>>>> read(), self.buffer=%s' % (self.buffer,) 
     73 
     74        if count == 0: 
     75            count = len(self.buffer) 
     76 
     77        ret = self.buffer[0:count] 
     78        #print 'ret = %s' % (ret,) 
     79        del self.buffer[0:count] 
     80        #print 'ret = %s' % (ret,) 
     81        return ret 
     82         
     83    def readSample(self): 
     84        return self.read()[0] 
     85 
     86 
     87    ####  Node Input 
     88    def write(self, data): 
     89        self.buffer += data 
     90        #print 'posting DATA_READY' 
     91        self.nc.post(self, 'DATA_READY') 
     92 
     93    def writeSample(self, data): 
     94        self.write((data,)) 
     95 
    4296class Input(object): 
    43     """An Input on a Node that receives incoming data.""" 
    44     source = None 
     97    """An Input on a Node that receives incoming data. 
     98     
     99    Signals: 
     100        DataRequest - This input is ready to read data from the connected output. 
     101    """ 
     102    def __init__(self): 
     103        self.source = None 
     104        self.nc = NotificationCenter() 
    45105 
    46106    def connect(self, output): 
    47107        """Associate this Input with the given Output so that the Input can pull data from the Output when necessary.""" 
    48108        self.source = output 
     109        self.nc.post(self, 'CONNECT') 
     110 
     111    def disconnect(self): 
     112        self.nc.post(self, 'DISCONNECT') 
     113        self.source = None 
     114 
     115    def write(self, data): 
     116        raise NotImplemented() 
    49117 
    50118class Output(object): 
    51     """An Output on a Node that sends data to Inputs.""" 
    52     signalListeners = [] 
     119    """An Output on a Node that sends data to Inputs. 
     120     
     121    Signals: 
     122        DataRead - Data is ready to be read from this output. 
     123    """ 
     124#    signalListeners = [] 
    53125 
    54126    def __init__(self): 
    55127        """Initialize a new Output.""" 
    56       self.signalListeners = {} 
     128#     self.signalListeners = {} 
    57129 
    58130    def read(self): 
    59131        """Read data from this Output if available.  If none is available then return None.  i.e. this is non-blocking.""" 
    60         pass 
    61  
    62     def addListener(self, listener, signal='all'): 
    63         self.signalListeners[signal].append(listener) 
    64  
    65     def tripSignal(self, signal): 
    66         if self.signalListeners.hasKey(signal): 
    67             listeners = self.signalListeners[signal] 
    68             for listener in listeners: 
    69                 listener(self, signal) 
    70  
    71  
    72 class NotificationCenter(Singleton): 
    73     def __init__(self): 
    74         self.listeners = {} 
    75  
    76     def _ensureListenerList(self, source, signal): 
    77         if not self.listeners.has_key((source, signal)): 
    78             self.listeners[(source, signal)] = [] 
    79  
    80     def addListener(self, source, signal, callable): 
    81         self._ensureListenerList(source, signal) 
    82         self.listeners[(source, signal)].append(callable) 
    83  
    84     def removeListener(self, source, signal, func): 
    85         key = (source, signal) 
    86         if self.listeners.has_key(key): 
    87             f = lambda x: x not func, 
    88             self.listeners[key] = filter(f, self.listeners[key]) 
    89  
    90     def post(self, source, signal): 
    91         key = (source, signal) 
    92         if self.listeners.has_key(key): 
    93             for f in self.listeners[key]: 
    94                 f(source, signal) 
    95  
    96  
    97 class PassthroughNode(Node): 
    98     class PassthroughOutput(Output): 
    99         def __init__(self, input=None): 
    100             if input is not None: 
    101                 self.source = input 
    102  
    103         def read(self): 
    104             return self.source 
    105  
    106     def __init__(self): 
    107         Node.__init__(self) 
    108         i = Input() 
    109         self.inputs.append(i) 
    110         self.outputs.append(PassthroughOutput(i)) 
     132        raise NotImplemented() 
     133 
     134#    def addListener(self, listener, signal): 
     135#       self.signalListeners[signal].append(listener) 
     136
     137#    def tripSignal(self, signal): 
     138#       if self.signalListeners.hasKey(signal): 
     139#           listeners = self.signalListeners[signal] 
     140#           for listener in listeners: 
     141#               listener(self, signal) 
     142 
    111143 
    112144 
     
    148180        return Singleton.__singletons[cls] 
    149181 
     182 
     183class NotificationCenter(Singleton): 
     184    def __init__(self): 
     185        self.listeners = {} 
     186 
     187    def _ensureListenerList(self, source, signal): 
     188        if not self.listeners.has_key((source, signal)): 
     189            self.listeners[(source, signal)] = [] 
     190 
     191    def addListener(self, source, signal, callable): 
     192        #print 'adding listener: source=%s, signal=%s, callable=%s' % (source, signal, callable) 
     193        self._ensureListenerList(source, signal) 
     194        self.listeners[(source, signal)].append(callable) 
     195 
     196    def removeListener(self, source, signal, func): 
     197        key = (source, signal) 
     198        if self.listeners.has_key(key): 
     199            f = lambda x: x is not func 
     200            self.listeners[key] = filter(f, self.listeners[key]) 
     201 
     202    def post(self, source, signal): 
     203        #print 'signal posted: (%s, %s)' % (source, signal) 
     204        key = (source, signal) 
     205        if self.listeners.has_key(key): 
     206            for f in self.listeners[key]: 
     207                #print '\tnotifying %s' % (f,) 
     208                f(source, signal) 
     209 
     210 
     211class PassthroughNode(Node): 
     212    def __init__(self): 
     213        Node.__init__(self) 
     214        i = NodeInputOutput() 
     215        self.inputs.append(i) 
     216        self.outputs.append(i) 
     217 
     218class ConsolePrintNode(Node): 
     219    def __init__(self): 
     220        Node.__init__(self) 
     221        self.nc = NotificationCenter() 
     222        i = Input() 
     223        self.nc.addListener(i, 'CONNECT', self.handleConnections) 
     224        self.nc.addListener(i, 'DISCONNECT', self.handleConnections) 
     225        self.inputs.append(i) 
     226 
     227    def handleConnections(self, node_input, signal): 
     228        output = node_input.source 
     229 
     230        if signal == 'CONNECT': 
     231            self.nc.addListener(output, 'DATA_READY', self.handleInput) 
     232        elif signal == 'DISCONNECT': 
     233            self.nc.removeListener(output, 'DATA_READY', self.handleInput) 
     234 
     235    def handleInput(self, node_output, signal): 
     236        #print '>>>> handleInput (node_output=%s, signal=%s)' % (node_output, signal) 
     237        if signal == 'DATA_READY': 
     238            data = node_output.read() 
     239            #print '\t\tdata=%s' % (data,) 
     240            for datum in data: 
     241                print "read: %s" % (datum,) 
     242 
     243class FuncOutput(NodeInputOutput): 
     244    def getFunc(self): 
     245        def f(*args, **kwargs): 
     246            self.writeSample((args, kwargs)) 
     247 
     248        return f