<s> """<STR_LIT>""" <EOL> from collections import defaultdict <EOL> import weakref <EOL> from . base import symbol , threading <EOL> from . import weakrefs <EOL> ANY = symbol ( '<STR_LIT>' ) <EOL> ANY_ID = <NUM_LIT:0> <EOL> class Signal ( object ) : <EOL> """<STR_LIT>""" <EOL> ANY = ANY <EOL> def __init__ ( self , doc = None ) : <EOL> if doc : <EOL> self . __doc__ = doc <EOL> self . receivers = { } <EOL> self . _by_receiver = defaultdict ( set ) <EOL> self . _by_sender = defaultdict ( set ) <EOL> self . _weak_senders = { } <EOL> def connect ( self , receiver , sender = ANY , weak = True ) : <EOL> """<STR_LIT>""" <EOL> receiver_id = _hashable_identity ( receiver ) <EOL> if weak : <EOL> receiver_ref = weakrefs . reference ( receiver , self . _cleanup_receiver ) <EOL> receiver_ref . receiver_id = receiver_id <EOL> else : <EOL> receiver_ref = receiver <EOL> sender_id = ANY_ID if sender is ANY else _hashable_identity ( sender ) <EOL> self . receivers . setdefault ( receiver_id , receiver_ref ) <EOL> self . _by_sender [ sender_id ] . add ( receiver_id ) <EOL> self . _by_receiver [ receiver_id ] . add ( sender_id ) <EOL> del receiver_ref <EOL> if sender is not ANY and sender_id not in self . _weak_senders : <EOL> try : <EOL> sender_ref = weakrefs . reference ( sender , self . _cleanup_sender ) <EOL> sender_ref . sender_id = sender_id <EOL> except TypeError : <EOL> pass <EOL> else : <EOL> self . _weak_senders . setdefault ( sender_id , sender_ref ) <EOL> del sender_ref <EOL> if receiver_connected . receivers and self is not receiver_connected : <EOL> try : <EOL> receiver_connected . send ( self , <EOL> receiver_arg = receiver , <EOL> sender_arg = sender , <EOL> weak_arg = weak ) <EOL> except : <EOL> self . disconnect ( receiver , sender ) <EOL> raise <EOL> return receiver <EOL> def send ( self , sender = None , ** kwargs ) : <EOL> """<STR_LIT>""" <EOL> if not self . receivers : <EOL> return [ ] <EOL> else : <EOL> return [ ( receiver , receiver ( sender = sender , ** kwargs ) ) <EOL> for receiver in self . receivers_for ( sender ) ] <EOL> def has_receivers_for ( self , sender ) : <EOL> """<STR_LIT>""" <EOL> if not self . receivers : <EOL> return False <EOL> if self . _by_sender [ ANY_ID ] : <EOL> return True <EOL> if sender is ANY : <EOL> return False <EOL> return _hashable_identity ( sender ) in self . _by_sender <EOL> def receivers_for ( self , sender ) : <EOL> """<STR_LIT>""" <EOL> if self . receivers : <EOL> sender_id = _hashable_identity ( sender ) <EOL> if sender_id in self . _by_sender : <EOL> ids = ( self . _by_sender [ ANY_ID ] | <EOL> self . _by_sender [ sender_id ] ) <EOL> else : <EOL> ids = self . _by_sender [ ANY_ID ] . copy ( ) <EOL> for receiver_id in ids : <EOL> receiver = self . receivers . get ( receiver_id ) <EOL> if receiver is None : <EOL> continue <EOL> if isinstance ( receiver , weakrefs . WeakTypes ) : <EOL> strong = receiver ( ) <EOL> if strong is None : <EOL> self . _disconnect ( receiver_id , ANY_ID ) <EOL> continue <EOL> receiver = strong <EOL> yield receiver <EOL> def disconnect ( self , receiver , sender = ANY ) : <EOL> """<STR_LIT>""" <EOL> sender_id = ANY_ID if sender is ANY else _hashable_identity ( sender ) <EOL> receiver_id = _hashable_identity ( receiver ) <EOL> self . _disconnect ( receiver_id , sender_id ) <EOL> def _disconnect ( self , receiver_id , sender_id ) : <EOL> if sender_id == ANY_ID : <EOL> if self . _by_receiver . pop ( receiver_id , False ) : <EOL> for bucket in self . _by_sender . values ( ) : <EOL> bucket . discard ( receiver_id ) <EOL> self . receivers . pop ( receiver_id , None ) <EOL> else : <EOL> self . _by_sender [ sender_id ] . discard ( receiver_id ) <EOL> def _cleanup_receiver ( self , receiver_ref ) : <EOL> """<STR_LIT>""" <EOL> self . _disconnect ( receiver_ref . receiver_id , ANY_ID ) <EOL> def _cleanup_sender ( self , sender_ref ) : <EOL> """<STR_LIT>""" <EOL> sender_id = sender_ref . sender_id <EOL> assert sender_id != ANY_ID <EOL> self . _weak_senders . pop ( sender_id , None ) <EOL> for receiver_id in self . _by_sender . pop ( sender_id , ( ) ) : <EOL> self . _by_receiver [ receiver_id ] . discard ( sender_id ) <EOL> def _clear_state ( self ) : <EOL> """<STR_LIT>""" <EOL> self . _weak_senders . clear ( ) <EOL> self . receivers . clear ( ) <EOL> self . _by_sender . clear ( ) <EOL> self . _by_receiver . clear ( ) <EOL> receiver_connected = Signal ( ) <EOL> class NamedSignal ( Signal ) : <EOL> """<STR_LIT>""" <EOL> def __init__ ( self , name , doc = None ) : <EOL> Signal . __init__ ( self , doc ) <EOL> self . name = name <EOL> def __repr__ ( self ) : <EOL> return '<STR_LIT>' % ( id ( self ) , self . name ) <EOL> class Namespace ( object ) : <EOL> """<STR_LIT>""" <EOL> storage_factory = weakref . WeakValueDictionary <EOL> signal_factory = NamedSignal <EOL> def __init__ ( self ) : <EOL> self . lock = threading . Lock ( ) <EOL> self . signals = self . storage_factory ( ) <EOL> def signal ( self , name , doc = None ) : <EOL> """<STR_LIT>""" <EOL> lock = self . lock <EOL> lock . acquire ( ) <EOL> try : <EOL> return self . signals [ name ] <EOL> except KeyError : <EOL> self . signals [ name ] = instance = self . signal_factory ( name , doc ) <EOL> return instance <EOL> finally : <EOL> lock . release ( ) <EOL> signal = Namespace ( ) . signal <EOL> def _hashable_identity ( obj ) : <EOL> if hasattr ( obj , '<STR_LIT>' ) : <EOL> return ( id ( obj . im_func ) , id ( obj . im_self ) ) <EOL> else : <EOL> return id ( obj ) </s>
