Ticket #6814: faster_signals.diff

File faster_signals.diff, 33.1 KB (added by Keith Bussell, 16 years ago)

Initial attempt at the signal refactor

  • django/core/signals.py

     
    1 request_started = object()
    2 request_finished = object()
    3 got_request_exception = object()
     1from django.dispatch.dispatcher import Signal
     2
     3request_started = Signal()
     4request_finished = Signal()
     5got_request_exception = Signal(argnames=["request"])
  • django/db/models/signals.py

     
    1 class_prepared = object()
     1from django.dispatch.dispatcher import Signal
    22
    3 pre_init= object()
    4 post_init = object()
     3class_prepared = Signal(argnames=["class"])
    54
    6 pre_save = object()
    7 post_save = object()
     5pre_init = Signal(argnames=["instance", "args", "kwargs"])
     6post_init = Signal(argnames=["instance"])
    87
    9 pre_delete = object()
    10 post_delete = object()
     8pre_save = Signal(argnames=["instance", "raw"])
     9post_save = Signal(argnames=["instance", "raw", "created"])
    1110
    12 post_syncdb = object()
     11pre_delete = Signal(argnames=["instance"])
     12post_delete = Signal(argnames=["instance"])
     13
     14post_syncdb = Signal(argnames=["class", "app", "created_models", "verbosity", "interactive"])
  • django/dispatch/dispatcher.py

     
    44providing the primary API and the core logic for the
    55system.
    66
    7 Module attributes of note:
    8 
    9     Any -- Singleton used to signal either "Any Sender" or
    10         "Any Signal".  See documentation of the _Any class.
    11     Anonymous -- Singleton used to signal "Anonymous Sender"
    12         See documentation of the _Anonymous class.
    13 
    147Internal attributes:
    158    WEAKREF_TYPES -- tuple of types/classes which represent
    169        weak references to receivers, and thus must be de-
    1710        referenced on retrieval to retrieve the callable
    1811        object
    19     connections -- { senderkey (id) : { signal : [receivers...]}}
    20     senders -- { senderkey (id) : weakref(sender) }
    21         used for cleaning up sender references on sender
    22         deletion
    23     sendersBack -- { receiverkey (id) : [senderkey (id)...] }
    24         used for cleaning up receiver references on receiver
    25         deletion, (considerably speeds up the cleanup process
    26         vs. the original code.)
    2712"""
    28 import types, weakref
    29 from django.dispatch import saferef, robustapply, errors
    3013
    3114__author__ = "Patrick K. O'Brien <pobrien@orbtech.com>"
    3215__cvsid__ = "$Id: dispatcher.py,v 1.9 2005/09/17 04:55:57 mcfletch Exp $"
    3316__version__ = "$Revision: 1.9 $"[11:-2]
    3417
     18import weakref
     19from django.dispatch import saferef, errors
    3520
    36 class _Parameter:
    37     """Used to represent default parameter values."""
    38     def __repr__(self):
    39         return self.__class__.__name__
    40 
    41 class _Any(_Parameter):
    42     """Singleton used to signal either "Any Sender" or "Any Signal"
    43 
    44     The Any object can be used with connect, disconnect,
    45     send, or sendExact to signal that the parameter given
    46     Any should react to all senders/signals, not just
    47     a particular sender/signal.
    48     """
    49 Any = _Any()
    50 
    51 class _Anonymous(_Parameter):
    52     """Singleton used to signal "Anonymous Sender"
    53 
    54     The Anonymous object is used to signal that the sender
    55     of a message is not specified (as distinct from being
    56     "any sender").  Registering callbacks for Anonymous
    57     will only receive messages sent without senders.  Sending
    58     with anonymous will only send messages to those receivers
    59     registered for Any or Anonymous.
    60 
    61     Note:
    62         The default sender for connect is Any, while the
    63         default sender for send is Anonymous.  This has
    64         the effect that if you do not specify any senders
    65         in either function then all messages are routed
    66         as though there was a single sender (Anonymous)
    67         being used everywhere.
    68     """
    69 Anonymous = _Anonymous()
    70 
    7121WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
    7222
    73 connections = {}
    74 senders = {}
    75 sendersBack = {}
    76 
    77 
    78 def connect(receiver, signal=Any, sender=Any, weak=True):
    79     """Connect receiver to sender for signal
    80 
    81     receiver -- a callable Python object which is to receive
    82         messages/signals/events.  Receivers must be hashable
    83         objects.
    84 
    85         if weak is True, then receiver must be weak-referencable
    86         (more precisely saferef.safeRef() must be able to create
    87         a reference to the receiver).
     23class Signal(object):
     24    """Base class for all signals
    8825   
    89         Receivers are fairly flexible in their specification,
    90         as the machinery in the robustApply module takes care
    91         of most of the details regarding figuring out appropriate
    92         subsets of the sent arguments to apply to a given
    93         receiver.
    94 
    95         Note:
    96             if receiver is itself a weak reference (a callable),
    97             it will be de-referenced by the system's machinery,
    98             so *generally* weak references are not suitable as
    99             receivers, though some use might be found for the
    100             facility whereby a higher-level library passes in
    101             pre-weakrefed receiver references.
    102 
    103     signal -- the signal to which the receiver should respond
     26    Internal attributes:
     27        receivers -- { receriverkey (id) : (weakref(receiver),
     28            acceptable_named_args, accepts_kwargs }
     29        sendersBack -- { receiverkey (id) : [senderkey (id)...] }
     30            used for cleaning up receiver references on receiver
     31            deletion, (considerably speeds up the cleanup process
     32            vs. the original code.)
     33    """
    10434   
    105         if Any, receiver will receive any signal from the
    106         indicated sender (which might also be Any, but is not
    107         necessarily Any).
    108        
    109         Otherwise must be a hashable Python object other than
    110         None (DispatcherError raised on None).
    111        
    112     sender -- the sender to which the receiver should respond
     35    def __init__(self, argnames=[]):
     36        """argnames -- A list of the arguments this signal can pass along in
     37                       a send() call.
     38        """
     39        self.receivers = {}
     40        self.sendersBack = {}
     41        self.argnames = set(argnames)
     42   
     43    def connect(self, receiver, sender=None, weak=True):
     44        """Connect receiver to sender for signal
    11345   
    114         if Any, receiver will receive the indicated signals
    115         from any sender.
     46        receiver -- a function or an instance method which is to
     47            receive messages/signals/events.  Receivers must be
     48            hashable objects.
     49   
     50            if weak is True, then receiver must be weak-referencable
     51            (more precisely saferef.safeRef() must be able to create
     52            a reference to the receiver).
    11653       
    117         if Anonymous, receiver will only receive indicated
    118         signals from send/sendExact which do not specify a
    119         sender, or specify Anonymous explicitly as the sender.
     54            Receivers must be able to accept the named arguments
     55            declared in argnames.
     56   
     57            Note:
     58                if receiver is itself a weak reference (a callable),
     59                it will be de-referenced by the system's machinery,
     60                so *generally* weak references are not suitable as
     61                receivers, though some use might be found for the
     62                facility whereby a higher-level library passes in
     63                pre-weakrefed receiver references.
     64           
     65        sender -- the sender to which the receiver should respond
     66            Must either be of type Signal, or None to receive events
     67            from any sender.
     68           
     69        weak -- whether to use weak references to the receiver
     70            By default, the module will attempt to use weak
     71            references to the receiver objects.  If this parameter
     72            is false, then strong references will be used.
     73   
     74        returns None
     75        """
     76        receiverkey = id(receiver)
     77        allowed_args = receiver.func_code.co_varnames
     78        accepts_kwargs = receiver.func_code.co_flags & 8
    12079
    121         Otherwise can be any python object.
    122        
    123     weak -- whether to use weak references to the receiver
    124         By default, the module will attempt to use weak
    125         references to the receiver objects.  If this parameter
    126         is false, then strong references will be used.
     80        if weak:
     81            receiver = saferef.safeRef(receiver, onDelete=self._removeReceiver)
     82           
     83        senderkey = id(sender)
    12784
    128     returns None, may raise DispatcherTypeError
    129     """
    130     if signal is None:
    131         raise errors.DispatcherTypeError(
    132             'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
    133         )
    134     if weak:
    135         receiver = saferef.safeRef(receiver, onDelete=_removeReceiver)
    136     senderkey = id(sender)
    137 
    138     signals = connections.setdefault(senderkey, {})
    139 
    140     # Keep track of senders for cleanup.
    141     # Is Anonymous something we want to clean up?
    142     if sender not in (None, Anonymous, Any):
    143         def remove(object, senderkey=senderkey):
    144             _removeSender(senderkey=senderkey)
    145         # Skip objects that can not be weakly referenced, which means
    146         # they won't be automatically cleaned up, but that's too bad.
    14785        try:
    148             weakSender = weakref.ref(sender, remove)
    149             senders[senderkey] = weakSender
    150         except:
     86            current = self.sendersBack.get( receiverkey )
     87            if current is None:
     88                self.sendersBack[ receiverkey ] = current = []
     89            if senderkey not in current:
     90                current.append(senderkey)
     91        except Exception, e:
    15192            pass
     93   
     94        self.receivers[receiverkey] = (receiver, set(allowed_args), accepts_kwargs)
    15295       
    153     receiverID = id(receiver)
    154     # get current set, remove any current references to
    155     # this receiver in the set, including back-references
    156     if signals.has_key(signal):
    157         receivers = signals[signal]
    158         _removeOldBackRefs(senderkey, signal, receiver, receivers)
    159     else:
    160         receivers = signals[signal] = []
    161     try:
    162         current = sendersBack.get( receiverID )
    163         if current is None:
    164             sendersBack[ receiverID ] = current = []
    165         if senderkey not in current:
    166             current.append(senderkey)
    167     except:
    168         pass
    169 
    170     receivers.append(receiver)
    171 
    172 
    173 
    174 def disconnect(receiver, signal=Any, sender=Any, weak=True):
    175     """Disconnect receiver from sender for signal
    176 
    177     receiver -- the registered receiver to disconnect
    178     signal -- the registered signal to disconnect
    179     sender -- the registered sender to disconnect
    180     weak -- the weakref state to disconnect
    181 
    182     disconnect reverses the process of connect,
    183     the semantics for the individual elements are
    184     logically equivalent to a tuple of
    185     (receiver, signal, sender, weak) used as a key
    186     to be deleted from the internal routing tables.
    187     (The actual process is slightly more complex
    188     but the semantics are basically the same).
    189 
    190     Note:
    191         Using disconnect is not required to cleanup
    192         routing when an object is deleted, the framework
    193         will remove routes for deleted objects
    194         automatically.  It's only necessary to disconnect
    195         if you want to stop routing to a live object.
     96    def disconnect(self, receiver, sender=None, weak=True):
     97        """Disconnect receiver from sender for signal
     98   
     99        receiver -- the registered receiver to disconnect
     100        sender -- the registered sender to disconnect
     101        weak -- the weakref state to disconnect
     102   
     103        disconnect reverses the process of connect,
     104        the semantics for the individual elements are
     105        logically equivalent to a tuple of
     106        (receiver, signal, sender, weak) used as a key
     107        to be deleted from the internal routing tables.
     108        (The actual process is slightly more complex
     109        but the semantics are basically the same).
     110   
     111        Note:
     112            Using disconnect is not required to cleanup
     113            routing when an object is deleted, the framework
     114            will remove routes for deleted objects
     115            automatically.  It's only necessary to disconnect
     116            if you want to stop routing to a live object.
     117           
     118        returns None, may raise DispatcherKeyError
     119        """
     120        receiverkey = id(receiver)
     121        if weak:
     122            receiver = saferef.safeRef(receiver)
    196123       
    197     returns None, may raise DispatcherTypeError or
    198         DispatcherKeyError
    199     """
    200     if signal is None:
    201         raise errors.DispatcherTypeError(
    202             'Signal cannot be None (receiver=%r sender=%r)'%( receiver,sender)
    203         )
    204     if weak: receiver = saferef.safeRef(receiver)
    205     senderkey = id(sender)
    206     try:
    207         signals = connections[senderkey]
    208         receivers = signals[signal]
    209     except KeyError:
    210         raise errors.DispatcherKeyError(
    211             """No receivers found for signal %r from sender %r""" %(
    212                 signal,
    213                 sender
    214             )
    215         )
    216     try:
    217         # also removes from receivers
    218         _removeOldBackRefs(senderkey, signal, receiver, receivers)
    219     except ValueError:
    220         raise errors.DispatcherKeyError(
    221             """No connection to receiver %s for signal %s from sender %s""" %(
    222                 receiver,
    223                 signal,
    224                 sender
    225             )
    226         )
    227     _cleanupConnections(senderkey, signal)
    228 
    229 def getReceivers( sender = Any, signal = Any ):
    230     """Get list of receivers from global tables
    231 
    232     This utility function allows you to retrieve the
    233     raw list of receivers from the connections table
    234     for the given sender and signal pair.
    235 
    236     Note:
    237         there is no guarantee that this is the actual list
    238         stored in the connections table, so the value
    239         should be treated as a simple iterable/truth value
    240         rather than, for instance a list to which you
    241         might append new records.
    242 
    243     Normally you would use liveReceivers( getReceivers( ...))
    244     to retrieve the actual receiver objects as an iterable
    245     object.
    246     """
    247     existing = connections.get(id(sender))
    248     if existing is not None:
    249         return existing.get(signal, [])
    250     return []
    251 
    252 def liveReceivers(receivers):
    253     """Filter sequence of receivers to get resolved, live receivers
    254 
    255     This is a generator which will iterate over
    256     the passed sequence, checking for weak references
    257     and resolving them, then returning all live
    258     receivers.
    259     """
    260     for receiver in receivers:
    261         if isinstance( receiver, WEAKREF_TYPES):
    262             # Dereference the weak reference.
    263             receiver = receiver()
    264             if receiver is not None:
    265                 yield receiver
    266         else:
    267             yield receiver
    268 
    269 
    270 
    271 def getAllReceivers( sender = Any, signal = Any ):
    272     """Get list of all receivers from global tables
    273 
    274     This gets all dereferenced receivers which should receive
    275     the given signal from sender, each receiver should
    276     be produced only once by the resulting generator
    277     """
    278     receivers = {}
    279     # Get receivers that receive *this* signal from *this* sender.
    280     # Add receivers that receive *any* signal from *this* sender.
    281     # Add receivers that receive *this* signal from *any* sender.
    282     # Add receivers that receive *any* signal from *any* sender.
    283     l = []
    284     i = id(sender)
    285     if i in connections:
    286         sender_receivers = connections[i]
    287         if signal in sender_receivers:
    288             l.extend(sender_receivers[signal])
    289         if signal is not Any and Any in sender_receivers:
    290             l.extend(sender_receivers[Any])
    291 
    292     if sender is not Any:
    293         i = id(Any)
    294         if i in connections:
    295             sender_receivers = connections[i]
    296             if sender_receivers is not None:
    297                 if signal in sender_receivers:
    298                     l.extend(sender_receivers[signal])
    299                 if signal is not Any and Any in sender_receivers:
    300                     l.extend(sender_receivers[Any])
    301 
    302     for receiver in l:
     124        # remove the backref to the sender
    303125        try:
    304             if not receiver in receivers:
    305                 if isinstance(receiver, WEAKREF_TYPES):
    306                     receiver = receiver()
    307                     # this should only (rough guess) be possible if somehow, deref'ing
    308                     # triggered a wipe.
    309                     if receiver is None:
    310                         continue
    311                 receivers[receiver] = 1
    312                 yield receiver
    313         except TypeError:
    314             # dead weakrefs raise TypeError on hash...
    315             pass
     126            senderkeys = self.sendersBack[receiverkey]
     127            del senderkeys[senderkeys.index(id(sender))]
     128        except (KeyError, ValueError):
     129            return False
    316130
    317 def send(signal=Any, sender=Anonymous, *arguments, **named):
    318     """Send signal from sender to all connected receivers.
     131        # if there are no more backrefs left, clean up the receiver
     132        try:
     133            if not senderkeys:
     134                del self.sendersBack[receiverkey]
     135                del self.receivers[receiverkey]
     136        except KeyError:
     137            return False
     138       
     139    def send(self, sender=None, **named):
     140        """Send signal from sender to all connected receivers.
     141       
     142        sender -- the sender of the signal
     143            Can be any python object (normally one registered with
     144            a connect if you actually want something to occur).
    319145   
    320     signal -- (hashable) signal value, see connect for details
    321 
    322     sender -- the sender of the signal
     146        named -- named arguments which will be passed to receivers.
     147            These arguments must be a subset of the argument names
     148            defined in argnames, or a DispatcherTypeError will be
     149            raised.
    323150   
    324         if Any, only receivers registered for Any will receive
    325         the message.
     151        Return a list of tuple pairs [(receiver, response), ... ],
     152        may raise DispatcherKeyError
     153       
     154        if any receiver raises an error, the error propagates back
     155        through send, terminating the dispatch loop, so it is quite
     156        possible to not have all receivers called if a raises an
     157        error.
     158        """
     159        # enforce the API
     160        for arg in named.keys():
     161            if arg not in self.argnames:
     162                raise errors.DispatcherTypeError, \
     163                    "send got an unexpected keyword argument '%s'" % arg
    326164
    327         if Anonymous, only receivers registered to receive
    328         messages from Anonymous or Any will receive the message
    329 
    330         Otherwise can be any python object (normally one
    331         registered with a connect if you actually want
    332         something to occur).
    333 
    334     arguments -- positional arguments which will be passed to
    335         *all* receivers. Note that this may raise TypeErrors
    336         if the receivers do not allow the particular arguments.
    337         Note also that arguments are applied before named
    338         arguments, so they should be used with care.
    339 
    340     named -- named arguments which will be filtered according
    341         to the parameters of the receivers to only provide those
    342         acceptable to the receiver.
    343 
    344     Return a list of tuple pairs [(receiver, response), ... ]
    345 
    346     if any receiver raises an error, the error propagates back
    347     through send, terminating the dispatch loop, so it is quite
    348     possible to not have all receivers called if a raises an
    349     error.
    350     """
    351     # Call each receiver with whatever arguments it can accept.
    352     # Return a list of tuple pairs [(receiver, response), ... ].
    353     responses = []
    354     for receiver in getAllReceivers(sender, signal):
    355         response = robustapply.robustApply(
    356             receiver,
    357             signal=signal,
    358             sender=sender,
    359             *arguments,
    360             **named
    361         )
    362         responses.append((receiver, response))
    363     return responses
    364 
    365 
    366 def sendExact( signal=Any, sender=Anonymous, *arguments, **named ):
    367     """Send signal only to those receivers registered for exact message
    368 
    369     sendExact allows for avoiding Any/Anonymous registered
    370     handlers, sending only to those receivers explicitly
    371     registered for a particular signal on a particular
    372     sender.
    373     """
    374     responses = []
    375     for receiver in liveReceivers(getReceivers(sender, signal)):
    376         response = robustapply.robustApply(
    377             receiver,
    378             signal=signal,
    379             sender=sender,
    380             *arguments,
    381             **named
    382         )
    383         responses.append((receiver, response))
    384     return responses
     165        senderkey = id(sender)
     166        none_senderkey = id(None)
     167       
     168        # Call each receiver.
     169        # Return a list of tuple pairs [(receiver, response), ... ].
     170        responses = []
     171        for receiverkey, receiver in self.liveReceivers():
     172            senderkeys = self.sendersBack[receiverkey]
     173            if none_senderkey in senderkeys or senderkey in senderkeys:
     174                response = self._callReceiver(
     175                    receiver,
     176                    receiverkey,
     177                    sender=sender,
     178                    signal=self,
     179                    **named)
     180                responses.append((receiver, response))
     181        return responses
    385182   
     183    def sendRobust(self, sender, **named):
     184        """Send signal from sender to all connected receivers catching errors
     185       
     186        sender -- the sender of the signal
     187            Can be any python object (normally one registered with
     188            a connect if you actually want something to occur).
     189   
     190        named -- named arguments which will be passed to receivers.
     191            These arguments must be a subset of the argument names
     192            defined in argnames, or a DispatcherTypeError will be
     193            raised.
     194   
     195        Return a list of tuple pairs [(receiver, response), ... ],
     196        may raise DispatcherKeyError
     197   
     198        if any receiver raises an error (specifically any subclass of Exception),
     199        the error instance is returned as the result for that receiver.
     200        """
     201        # enforce the API
     202        for arg in named.keys():
     203            if arg not in self.argnames:
     204                raise DispatcherTypeError, "send got an unexpected keyword argument '%s'" % arg
    386205
    387 def _removeReceiver(receiver):
    388     """Remove receiver from connections."""
    389     if not sendersBack:
    390         # During module cleanup the mapping will be replaced with None
    391         return False
    392     backKey = id(receiver)
    393     for senderkey in sendersBack.get(backKey,()):
    394         try:
    395             signals = connections[senderkey].keys()
    396         except KeyError,err:
    397             pass
    398         else:
    399             for signal in signals:
    400                 try:
    401                     receivers = connections[senderkey][signal]
    402                 except KeyError:
    403                     pass
    404                 else:
    405                     try:
    406                         receivers.remove( receiver )
    407                     except Exception, err:
    408                         pass
    409                 _cleanupConnections(senderkey, signal)
    410     try:
    411         del sendersBack[ backKey ]
    412     except KeyError:
    413         pass
    414            
    415 def _cleanupConnections(senderkey, signal):
    416     """Delete any empty signals for senderkey. Delete senderkey if empty."""
    417     try:
    418         receivers = connections[senderkey][signal]
    419     except:
    420         pass
    421     else:
    422         if not receivers:
    423             # No more connected receivers. Therefore, remove the signal.
     206        # Call each receiver with whatever arguments it can accept.
     207        # Return a list of tuple pairs [(receiver, response), ... ].
     208        responses = []
     209        for receiverkey, receiver in self.liveReceivers():
    424210            try:
    425                 signals = connections[senderkey]
    426             except KeyError:
    427                 pass
     211                response = self._callReceiver(
     212                    receiver,
     213                    receiverkey,
     214                    sender=sender,
     215                    signal=self,
     216                    **named)
     217            except Exception, err:
     218                responses.append((receiver, err))
    428219            else:
    429                 del signals[signal]
    430                 if not signals:
    431                     # No more signal connections. Therefore, remove the sender.
    432                     _removeSender(senderkey)
     220                responses.append((receiver, response))
     221        return responses
    433222
    434 def _removeSender(senderkey):
    435     """Remove senderkey from connections."""
    436     _removeBackrefs(senderkey)
     223    def liveReceivers(self):
     224        """Filter sequence of receivers to get resolved, live receivers
     225   
     226        This is a generator which will iterate over
     227        the passed sequence, checking for weak references
     228        and resolving them, then returning all live
     229        receivers.
     230        """
     231        for (receiverkey, receiver) in self.receivers.items():
     232            receiver = receiver[0]
     233            if isinstance(receiver, WEAKREF_TYPES):
     234                # Dereference the weak reference.
     235                receiver = receiver()
     236                if receiver is not None:
     237                    yield receiverkey, receiver
     238            else:
     239                yield receiverkey, receiver
    437240
    438     connections.pop(senderkey, None)
    439     senders.pop(senderkey, None)
    440 
    441 
    442 def _removeBackrefs( senderkey):
    443     """Remove all back-references to this senderkey"""
    444     for receiver_list in connections.pop(senderkey, {}).values():
    445         for receiver in receiver_list:
    446             _killBackref( receiver, senderkey )
    447 
    448 
    449 def _removeOldBackRefs(senderkey, signal, receiver, receivers):
    450     """Kill old sendersBack references from receiver
    451 
    452     This guards against multiple registration of the same
    453     receiver for a given signal and sender leaking memory
    454     as old back reference records build up.
    455 
    456     Also removes old receiver instance from receivers
    457     """
    458     try:
    459         index = receivers.index(receiver)
    460         # need to scan back references here and remove senderkey
    461     except ValueError:
    462         return False
    463     else:
    464         oldReceiver = receivers[index]
    465         del receivers[index]
    466         found = 0
    467         signals = connections.get(signal)
    468         if signals is not None:
    469             for sig,recs in connections.get(signal,{}).iteritems():
    470                 if sig != signal:
    471                     for rec in recs:
    472                         if rec is oldReceiver:
    473                             found = 1
    474                             break
    475         if not found:
    476             _killBackref( oldReceiver, senderkey )
    477             return True
    478         return False
     241    def _callReceiver(self, receiver, receiverkey, **named):
     242        receiver_info = self.receivers[receiverkey]
     243        if not receiver_info[2]:
     244            acceptable_args = receiver_info[1]
     245            for arg in named.keys():
     246                if arg not in acceptable_args:
     247                    del named[arg]
     248        return receiver(**named)
    479249       
     250    def _removeReceiver(self, receiver):
     251        """Remove receiver from connections."""
     252        if not self.sendersBack:
     253            # TODO: Is this still true?
     254            # During module cleanup the mapping will be replaced with None
     255            return False
     256        backKey = id(receiver)
    480257       
    481 def _killBackref( receiver, senderkey ):
    482     """Do the actual removal of back reference from receiver to senderkey"""
    483     receiverkey = id(receiver)
    484     receivers_list = sendersBack.get( receiverkey, () )
    485     while senderkey in receivers_list:
    486258        try:
    487             receivers_list.remove( senderkey )
    488         except:
    489             break
    490     if not receivers_list:
     259            del self.sendersBack[backKey]
     260        except KeyError:
     261            pass
    491262        try:
    492             del sendersBack[ receiverkey ]
     263            del self.receivers[backKey]
    493264        except KeyError:
    494265            pass
    495     return True
     266
     267def connect(receiver, signal, sender=None, weak=True):
     268    """For backward compatibility only. See Signal.connect()
     269    """
     270    return signal.connect(receiver, sender, weak)
     271
     272def disconnect(receiver, signal, sender=None, weak=True):
     273    """For backward compatibility only. See Signal.disconnect()
     274    """
     275    signal.disconnect(receiver, sender, weak)
     276
     277def send(signal, sender=None, **named):
     278    """For backward compatibility only. See Signal.send()
     279    """
     280    return signal.send(sender=sender, **named)
     281
     282def sendExact(signal, sender, **named ):
     283    """This function is deprecated, as it now has the same
     284    meaning as send.
     285    """
     286    return signal.send(sender=sender, **named)
     287   
     288 No newline at end of file
  • django/dispatch/robust.py

     
    11"""Module implementing error-catching version of send (sendRobust)"""
    2 from django.dispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers
    3 from django.dispatch.robustapply import robustApply
     2from django.dispatch.dispatcher import Signal
    43
    5 def sendRobust(
    6     signal=Any,
    7     sender=Anonymous,
    8     *arguments, **named
    9 ):
    10     """Send signal from sender to all connected receivers catching errors
    11    
    12     signal -- (hashable) signal value, see connect for details
    13 
    14     sender -- the sender of the signal
    15    
    16         if Any, only receivers registered for Any will receive
    17         the message.
    18 
    19         if Anonymous, only receivers registered to receive
    20         messages from Anonymous or Any will receive the message
    21 
    22         Otherwise can be any python object (normally one
    23         registered with a connect if you actually want
    24         something to occur).
    25 
    26     arguments -- positional arguments which will be passed to
    27         *all* receivers. Note that this may raise TypeErrors
    28         if the receivers do not allow the particular arguments.
    29         Note also that arguments are applied before named
    30         arguments, so they should be used with care.
    31 
    32     named -- named arguments which will be filtered according
    33         to the parameters of the receivers to only provide those
    34         acceptable to the receiver.
    35 
    36     Return a list of tuple pairs [(receiver, response), ... ]
    37 
    38     if any receiver raises an error (specifically any subclass of Exception),
    39     the error instance is returned as the result for that receiver.
     4def sendRobust(signal, sender, **named):
     5    """For backward compatibility only. See Signal.sendRobust()
    406    """
    41     # Call each receiver with whatever arguments it can accept.
    42     # Return a list of tuple pairs [(receiver, response), ... ].
    43     responses = []
    44     for receiver in liveReceivers(getAllReceivers(sender, signal)):
    45         try:
    46             response = robustApply(
    47                 receiver,
    48                 signal=signal,
    49                 sender=sender,
    50                 *arguments,
    51                 **named
    52             )
    53         except Exception, err:
    54             responses.append((receiver, err))
    55         else:
    56             responses.append((receiver, response))
    57     return responses
     7    return signal.sendRobust(sender=sender, **named)
  • django/dispatch/saferef.py

     
    33from django.utils.functional import curry
    44
    55def safeRef(target, onDelete = None):
    6     """Return a *safe* weak reference to a callable target
     6    """Return a tuple of a *safe* weak reference to a callable
     7    target and the id of that object.
    78
    89    target -- the object to be weakly referenced, if it's a
    910        bound method reference, will create a BoundMethodWeakref,
     
    2324                onDelete=onDelete
    2425            )
    2526            return reference
     27    # If a weakref is created using
    2628    if callable(onDelete):
    2729        return weakref.ref(target, onDelete)
    2830    else:
     
    234236        return BoundMethodWeakref(target=target, onDelete=onDelete)
    235237    else:
    236238        # no luck, use the alternative implementation:
    237         return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete)
    238 
     239        return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete)
     240 No newline at end of file
  • django/test/signals.py

     
    1 template_rendered = object()
    2  No newline at end of file
     1from django.dispatch.dispatcher import Signal
     2
     3template_rendered = Signal(argnames=["template", "context"])
     4 No newline at end of file
  • tests/regressiontests/dispatch/tests/__init__.py

     
    22Unit-tests for the dispatch project
    33"""
    44
    5 from test_dispatcher import *
    6 from test_robustapply import *
    75from test_saferef import *
Back to Top