Ticket #6814: faster_signals-2.diff
| File faster_signals-2.diff, 53.4 kB (added by jdunck, 10 months ago) |
|---|
-
django/test/signals.py
old new -
django/db/models/signals.py
old new 1 class_prepared = object() 1 from django.dispatch.dispatcher import Signal 2 2 3 pre_init= object() 4 post_init = object() 3 class_prepared = Signal() 5 4 6 pre_ save = object()7 post_ save = object()5 pre_init = Signal(providing_args=["args", "kwargs"]) 6 post_init = Signal(providing_args=["instance"]) 8 7 9 pre_ delete = object()10 post_ delete = object()8 pre_save = Signal(providing_args=["instance", "raw"]) 9 post_save = Signal(providing_args=["instance", "raw", "created"]) 11 10 12 post_syncdb = object() 11 pre_delete = Signal(providing_args=["instance"]) 12 post_delete = Signal(providing_args=["instance"]) 13 14 post_syncdb = Signal(providing_args=["app", "created_models", "verbosity", "interactive"]) -
django/core/signals.py
old new 1 request_started = object() 2 request_finished = object() 3 got_request_exception = object() 1 from django.dispatch.dispatcher import Signal 2 3 request_started = Signal() 4 request_finished = Signal() 5 got_request_exception = Signal(providing_args=["request"]) -
django/dispatch/license.txt
old new 1 PyDispatcher License2 3 Copyright (c) 2001-2003, Patrick K. O'Brien and Contributors4 All rights reserved.5 6 Redistribution and use in source and binary forms, with or without7 modification, are permitted provided that the following conditions8 are met:9 10 Redistributions of source code must retain the above copyright11 notice, this list of conditions and the following disclaimer.12 13 Redistributions in binary form must reproduce the above14 copyright notice, this list of conditions and the following15 disclaimer in the documentation and/or other materials16 provided with the distribution.17 18 The name of Patrick K. O'Brien, or the name of any Contributor,19 may not be used to endorse or promote products derived from this20 software without specific prior written permission.21 22 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS23 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT24 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS25 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE26 COPYRIGHT HOLDERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT,27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR29 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)30 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,31 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED33 OF THE POSSIBILITY OF SUCH DAMAGE.34 -
django/dispatch/saferef.py
old new 3 3 from django.utils.functional import curry 4 4 5 5 def 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. 7 8 8 9 target -- the object to be weakly referenced, if it's a 9 10 bound method reference, will create a BoundMethodWeakref, … … 23 24 onDelete=onDelete 24 25 ) 25 26 return reference 27 # If a weakref is created using 26 28 if callable(onDelete): 27 29 return weakref.ref(target, onDelete) 28 30 else: … … 234 236 return BoundMethodWeakref(target=target, onDelete=onDelete) 235 237 else: 236 238 # no luck, use the alternative implementation: 237 return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete) 238 239 return BoundNonDescriptorMethodWeakref(target=target, onDelete=onDelete) -
django/dispatch/errors.py
old new 3 3 4 4 class DispatcherError(Exception): 5 5 """Base class for all Dispatcher errors""" 6 class DispatcherKeyError(KeyError, DispatcherError):7 """Error raised when unknown (sender,signal) set specified"""8 6 class DispatcherTypeError(TypeError, DispatcherError): 9 7 """Error raised when inappropriate signal-type specified (None)""" 10 8 -
django/dispatch/robust.py
old new 1 """Module implementing error-catching version of send (sendRobust)"""2 from django.dispatch.dispatcher import Any, Anonymous, liveReceivers, getAllReceivers3 from django.dispatch.robustapply import robustApply4 5 def sendRobust(6 signal=Any,7 sender=Anonymous,8 *arguments, **named9 ):10 """Send signal from sender to all connected receivers catching errors11 12 signal -- (hashable) signal value, see connect for details13 14 sender -- the sender of the signal15 16 if Any, only receivers registered for Any will receive17 the message.18 19 if Anonymous, only receivers registered to receive20 messages from Anonymous or Any will receive the message21 22 Otherwise can be any python object (normally one23 registered with a connect if you actually want24 something to occur).25 26 arguments -- positional arguments which will be passed to27 *all* receivers. Note that this may raise TypeErrors28 if the receivers do not allow the particular arguments.29 Note also that arguments are applied before named30 arguments, so they should be used with care.31 32 named -- named arguments which will be filtered according33 to the parameters of the receivers to only provide those34 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.40 """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 **named52 )53 except Exception, err:54 responses.append((receiver, err))55 else:56 responses.append((receiver, response))57 return responses -
django/dispatch/__init__.py
old new 4 4 __author__ = "Patrick K. O'Brien" 5 5 __license__ = "BSD-style, see license.txt for details" 6 6 7 """ 8 new - weak_dict 9 0 receivers test 1.70392489433 10 1 receiver test 11.3397159576 1.23367714882 11 """ 12 """ 13 new - strong dict 14 0 receivers test 2.07081604004 15 1 receiver test 7.21637010574 1.23387694359 16 10 receivers test 24.1335361004 4.61771893501 17 """ -
django/dispatch/dispatcher_weak_dict.py
old new 1 import weakref 2 import inspect 3 4 try: 5 set 6 except NameError: 7 from sets import Set as set # For Python 2.3 8 9 from django.dispatch import saferef, errors 10 11 WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref) 12 13 class Signal(object): 14 """Base class for all signals 15 16 Internal attributes: 17 receivers -- { receiver_key (id) : (receiver, 18 acceptable_named_args, 19 accepts_kwargs) } 20 """ 21 def __init__(self, providing_args=[]): 22 """providing_args -- A list of the arguments this signal can pass along in 23 a send() call. 24 """ 25 self._receivers = {} 26 self.providing_args = set(providing_args) 27 28 def connect(self, receiver, sender=None, weak=False): 29 """Connect receiver to sender for signal 30 31 receiver -- a function or an instance method which is to 32 receive messages/signals/events. Receivers must be 33 hashable objects. 34 35 if weak is True, then receiver must be weak-referencable 36 (more precisely saferef.safeRef() must be able to create 37 a reference to the receiver). 38 39 Receivers must be able to accept the named arguments 40 declared in providing_args. 41 42 Note: 43 if receiver is itself a weak reference (a callable), 44 it will be de-referenced by the system's machinery, 45 so *generally* weak references are not suitable as 46 receivers, though some use might be found for the 47 facility whereby a higher-level library passes in 48 pre-weakrefed receiver references. 49 50 sender -- the sender to which the receiver should respond 51 Must either be of type Signal, or None to receive events 52 from any sender. 53 54 weak -- whether to use weak references to the receiver 55 By default, the module will attempt to use weak 56 references to the receiver objects. If this parameter 57 is false, then strong references will be used. 58 59 returns None 60 """ 61 allowed_args, _, kw_var, _ = inspect.getargspec(receiver) 62 accepts_kwargs = kw_var is not None 63 64 receiver_key = (id(sender), id(receiver)) 65 66 if weak: 67 receiver = saferef.safeRef(receiver) 68 69 self._receivers[receiver_key] = (receiver, set(allowed_args), accepts_kwargs) 70 71 def disconnect(self, receiver, sender=None, weak=True): 72 """Disconnect receiver from sender for signal 73 74 receiver -- the registered receiver to disconnect 75 sender -- the registered sender to disconnect, or None 76 if the receiver should be disconnected from all. 77 weak -- deprecated and ignored. 78 79 disconnect reverses the process of connect. 80 81 Note: 82 Using disconnect is not required to cleanup 83 routing when an object is deleted, the framework 84 will skip routes for deleted objects 85 automatically. It's only necessary to disconnect 86 if you want to stop routing to a live object. 87 88 returns None 89 """ 90 receiver_key = (id(sender), id(receiver)) 91 try: 92 del self._receivers[receiver_key] 93 except KeyError: 94 return False 95 96 def send(self, sender, **named): 97 """ 98 Send signal from sender to all connected receivers. 99 100 sender -- the sender of the signal 101 Can be any python object (normally one registered with 102 a connect if you actually want something to occur). 103 104 named -- named arguments which will be passed to receivers. 105 These arguments must be a subset of the argument names 106 defined in providing_args, or a DispatcherTypeError will be 107 raised. 108 109 Return a list of tuple pairs [(receiver, response), ... ]. 110 111 An exception from any receiver halts dispatch and propagates 112 back through send. 113 """ 114 responses = [] 115 if not self._receivers: 116 return responses 117 118 self._enforce_send_api(named) #FIXME: 20% speedup in send if we take this out 119 for receiver_key, receiver_info in self.get_live_receivers(sender): 120 receiver, allowed_args, accepts_kwargs = receiver_info 121 122 allowed = named.copy() 123 allowed['sender'] = sender 124 125 if not accepts_kwargs: 126 for arg in allowed.keys(): 127 if arg not in allowed_args: 128 del allowed[arg] 129 130 responses.append((receiver, receiver(**allowed))) 131 return responses 132 133 def get_live_receivers(self, sender): 134 """ 135 Returns an iterable over all live receivers for the signal. 136 """ 137 listening_to_all = id(None) 138 sending_from = id(sender) 139 for ((listen_to_id, receiver_id), receiver_info) in self._receivers.items(): 140 if listen_to_id != listening_to_all and sending_from != listen_to_id: 141 continue 142 receiver_, allowed_args, accepts_kwargs = receiver_info 143 if not self._receiver_is_live(receiver_): 144 del self._receivers[(listen_to_id, receiver_id)] 145 continue 146 yield (sending_from, receiver_id), (self._get_receiver(receiver_), allowed_args, accepts_kwargs) 147 148 149 def _get_receiver(self, receiver): 150 if isinstance(receiver, WEAKREF_TYPES): 151 return receiver() 152 else: 153 return receiver 154 155 def _receiver_is_live(self, receiver): 156 return bool(self._get_receiver(receiver) is not None) 157 158 def _enforce_send_api(self, sent_names): 159 """ 160 Ensures that send calls are made with the parameters declared 161 in Signal construction. 162 """ 163 sent_names_set = set(sent_names.keys()) 164 165 if sent_names_set != self.providing_args: 166 pluralize = lambda qty: qty != 1 and 's' or '' 167 flatten = lambda s: ",".join([str(item) for item in s]) 168 169 extras = sent_names_set - self.providing_args 170 missing = self.providing_args - sent_names_set 171 172 message = "Signal.send" 173 if extras: 174 message += " got unexpected argment%s: %s" % (pluralize(len(extras)), flatten(extras)) 175 if missing: 176 if extras: 177 message += " and" 178 message += " missing expected argment%s: %s" % (pluralize(len(missing)), flatten(missing)) 179 180 raise errors.DispatcherTypeError, message 181 182 183 def connect(receiver, signal, sender=None, weak=True): 184 """For backward compatibility only. See Signal.connect() 185 """ 186 return signal.connect(receiver, sender, weak) 187 188 def disconnect(receiver, signal, sender=None, weak=True): 189 """For backward compatibility only. See Signal.disconnect() 190 """ 191 signal.disconnect(receiver, sender, weak) 192 193 def send(signal, sender=None, **named): 194 """For backward compatibility only. See Signal.send() 195 """ 196 return signal.send(sender=sender, **named) 197 198 def sendExact(signal, sender, **named ): 199 """This function is deprecated, as it now has the same 200 meaning as send. 201 """ 202 return signal.send(sender=sender, **named) -
django/dispatch/robustapply.py
old new 1 """Robust apply mechanism2 3 Provides a function "call", which can sort out4 what arguments a given callable object can take,5 and subset the given arguments to match only6 those which are acceptable.7 """8 9 def function( receiver ):10 """Get function-like callable object for given receiver11 12 returns (function_or_method, codeObject, fromMethod)13 14 If fromMethod is true, then the callable already15 has its first argument bound16 """17 if hasattr(receiver, '__call__'):18 # receiver is a class instance; assume it is callable.19 # Reassign receiver to the actual method that will be called.20 if hasattr( receiver.__call__, 'im_func') or hasattr( receiver.__call__, 'im_code'):21 receiver = receiver.__call__22 if hasattr( receiver, 'im_func' ):23 # an instance-method...24 return receiver, receiver.im_func.func_code, 125 elif not hasattr( receiver, 'func_code'):26 raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver)))27 return receiver, receiver.func_code, 028 29 def robustApply(receiver, *arguments, **named):30 """Call receiver with arguments and an appropriate subset of named31 """32 receiver, codeObject, startIndex = function( receiver )33 acceptable = codeObject.co_varnames[startIndex+len(arguments):codeObject.co_argcount]34 for name in codeObject.co_varnames[startIndex:startIndex+len(arguments)]:35 if named.has_key( name ):36 raise TypeError(37 """Argument %r specified both positionally and as a keyword for calling %r"""% (38 name, receiver,39 )40 )41 if not (codeObject.co_flags & 8):42 # fc does not have a **kwds type parameter, therefore43 # remove unacceptable arguments.44 for arg in named.keys():45 if arg not in acceptable:46 del named[arg]47 return receiver(*arguments, **named) -
django/dispatch/dispatcher_strong_dict.py
old new 1 import inspect 2 3 try: 4 set 5 except NameError: 6 from sets import Set as set # For Python 2.3 7 8 from django.dispatch import errors 9 10 class Signal(object): 11 """Base class for all signals 12 13 Internal attributes: 14 receivers -- { receiver_key (id) : (receiver, 15 acceptable_named_args, 16 accepts_kwargs) } 17 """ 18 19 def __init__(self, providing_args=[]): 20 """providing_args -- A list of the arguments this signal can pass along in 21 a send() call. 22 """ 23 self._receivers = {} 24 self.providing_args = set(providing_args) 25 26 def connect(self, receiver, sender=None): 27 """Connect receiver to sender for signal 28 29 receiver -- a function or an instance method which is to 30 receive messages/signals/events. Receivers must be 31 hashable objects. 32 33 Receivers must be able to accept the named arguments 34 declared in providing_args. 35 36 sender -- the sender to which the receiver should respond 37 Must either be of type Signal, or None to receive events 38 from any sender. 39 40 returns None 41 """ 42 allowed_args, _, kw_var, _ = inspect.getargspec(receiver) 43 accepts_kwargs = kw_var is not None 44 45 receiver_key = (id(sender), id(receiver)) 46 47 self._receivers[receiver_key] = (receiver, set(allowed_args), accepts_kwargs) 48 49 def disconnect(self, receiver, sender=None): 50 """Disconnect receiver from sender for signal 51 52 receiver -- the registered receiver to disconnect 53 sender -- the registered sender to disconnect, or None 54 if the receiver should be disconnected from all. 55 56 disconnect reverses the process of connect. 57 58 Note: 59 Using disconnect is not required to cleanup 60 routing when an object is deleted, the framework 61 will skip routes for deleted objects 62 automatically. It's only necessary to disconnect 63 if you want to stop routing to a live object. 64 65 returns None 66 """ 67 receiver_key = (id(sender), id(receiver)) 68 try: 69 del self._receivers[receiver_key] 70 except KeyError: 71 return False 72 73 def send(self, sender, **named): 74 """ 75 Send signal from sender to all connected receivers. 76 77 sender -- the sender of the signal 78 Can be any python object (normally one registered with 79 a connect if you actually want something to occur). 80 81 named -- named arguments which will be passed to receivers. 82 These arguments must be a subset of the argument names 83 defined in providing_args, or a DispatcherTypeError will be 84 raised. 85 86 Return a list of tuple pairs [(receiver, response), ... ]. 87 88 An exception from any receiver halts dispatch and propagates 89 back through send. 90 """ 91 responses = [] 92 if len(self._receivers) == 0: 93 return responses 94 95 self._enforce_send_api(named) #FIXME: 20% speedup in send if we take this out 96 97 listening_to_all = id(None) 98 sending_from = id(sender) 99 100 for ((listen_to_id, receiver_id), receiver_info) in self._receivers.items(): 101 if listen_to_id != listening_to_all and sending_from != listen_to_id: 102 continue 103 104 receiver, allowed_args, accepts_kwargs = receiver_info 105 106 allowed = named.copy() 107 allowed['sender'] = sender 108 109 if not accepts_kwargs: 110 for arg in allowed.keys(): 111 if arg not in allowed_args: 112 del allowed[arg] 113 114 responses.append((receiver, receiver(**allowed))) 115 return responses 116 117 def _enforce_send_api(self, sent_names): 118 """ 119 Ensures that send calls are made with the parameters declared 120 in Signal construction. 121 """ 122 sent_names_set = set(sent_names.keys()) 123 124 if sent_names_set != self.providing_args: 125 pluralize = lambda qty: qty != 1 and 's' or '' 126 flatten = lambda s: ",".join([str(item) for item in s]) 127 128 extras = sent_names_set - self.providing_args 129 missing = self.providing_args - sent_names_set 130 131 message = "Signal.send" 132 if extras: 133 message += " got unexpected argment%s: %s" % (pluralize(len(extras)), flatten(extras)) 134 if missing: 135 if extras: 136 message += " and" 137 message += " missing expected argment%s: %s" % (pluralize(len(missing)), flatten(missing)) 138 139 raise errors.DispatcherTypeError, message 140 141 142 def connect(receiver, signal, sender=None): 143 """For backward compatibility only. See Signal.connect() 144 """ 145 return signal.connect(receiver, sender) 146 147 def disconnect(receiver, signal, sender=None): 148 """For backward compatibility only. See Signal.disconnect() 149 """ 150 signal.disconnect(receiver, sender) 151 152 def send(signal, sender=None, **named): 153 """For backward compatibility only. See Signal.send() 154 """ 155 return signal.send(sender=sender, **named) 156 157 def sendExact(signal, sender, **named): 158 """This function is deprecated, as it now has the same 159 meaning as send. 160 """ 161 return signal.send(sender=sender, **named) -
django/dispatch/dispatcher.py
old new 1 """Multiple-producer-multiple-consumer signal-dispatching 1 import inspect 2 2 3 dispatcher is the core of the PyDispatcher system, 4 providing the primary API and the core logic for the 5 system. 3 try: 4 set 5 except NameError: 6 from sets import Set as set # For Python 2.3 6 7 7 Module attributes of note: 8 from django.dispatch import errors 8 9 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. 10 pluralize = lambda qty: qty != 1 and 's' or '' 11 flatten = lambda s: ",".join([str(item) for item in s]) 13 12 14 Internal attributes: 15 WEAKREF_TYPES -- tuple of types/classes which represent 16 weak references to receivers, and thus must be de- 17 referenced on retrieval to retrieve the callable 18 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.) 27 """ 28 import types, weakref 29 from django.dispatch import saferef, robustapply, errors 30 31 __author__ = "Patrick K. O'Brien <pobrien@orbtech.com>" 32 __cvsid__ = "$Id: dispatcher.py,v 1.9 2005/09/17 04:55:57 mcfletch Exp $" 33 __version__ = "$Revision: 1.9 $"[11:-2] 34 35 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. 13 class Signal(object): 48 14 """ 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. 15 Internal attributes: 16 _receivers -- { receiver_key (id) : (sender_id, 17 receiver, 18 acceptable_named_args, 19 accepts_kwargs) } 68 20 """ 69 Anonymous = _Anonymous()70 71 WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)72 73 connections = {}74 senders = {}75 sendersBack = {}76 77 78 def connect(receiver, signal=Any, sender=Any, weak=True):79 """Connect receiver to sender for signal80 81 receiver -- a callable Python object which is to receive82 messages/signals/events. Receivers must be hashable83 objects.84 85 if weak is True, then receiver must be weak-referencable86 (more precisely saferef.safeRef() must be able to create87 a reference to the receiver).88 21 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 22 def __init__(self, providing_args=[]): 23 """providing_args -- A list of the arguments this signal will pass along in 24 a send() call. 25 """ 26 self._receivers = [] 27 self.providing_args = set(providing_args) 104 28 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 29 def connect(self, receiver, sender=None): 30 """Connect receiver to sender for signal 113 31 114 if Any, receiver will receive the indicated signals 115 from any sender. 32 receiver -- a function or an instance method which is to 33 receive messages/signals/events. Receivers must be 34 hashable objects. 35 36 Receivers must be able to accept the named arguments 37 declared in providing_args. 38 39 sender -- the sender to which the receiver should respond 40 Must either be of type Signal, or None to receive events 41 from any sender. 42 43 returns None 44 """ 45 allowed_args, _, kw_var, _ = inspect.getargspec(receiver) 46 allowed_args = set(allowed_args) 47 accepts_kwargs = kw_var is not None 116 48 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. 120 121 Otherwise can be any python object. 49 if not accepts_kwargs: 50 self._enforce_receive_api(receiver, allowed_args) 122 51 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. 52 sender_id = id(sender) 53 receiver_id = id(receiver) 127 54 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. 147 try: 148 weakSender = weakref.ref(sender, remove) 149 senders[senderkey] = weakSender 150 except: 151 pass 55 for existing_sender_id, existing_receiver, _, _ in self._receivers: 56 if self._receiver_match(existing_sender_id, id(existing_receiver), sender_id, receiver_id): 57 return 58 receiver_info = (sender_id, receiver, allowed_args, accepts_kwargs) 59 self._receivers.append(receiver_info) 152 60 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 61 def disconnect(self, receiver, sender=None): 62 """Disconnect receiver from sender for signal 63 64 receiver -- the registered receiver to disconnect 65 sender -- the registered sender to disconnect, or None 66 if the receiver should be disconnected from all. 67 68 disconnect reverses the process of connect. 69 70 Note: 71 Using disconnect is not required to cleanup 72 routing when an object is deleted, the framework 73 will skip routes for deleted objects 74 automatically. It's only necessary to disconnect 75 if you want to stop routing to a live object. 76 77 returns None 78 """ 79 requested_sender_id = id(sender) 80 requested_receiver_id = id(receiver) 169 81 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. 82 for i, (sender_id, receiver, _, _) in enumerate(self._receivers): 83 if self._receiver_match(requested_sender_id, 84 requested_receiver_id, 85 sender_id, 86 id(receiver)): 87 self._receivers.pop(i) 88 return True 89 return False 90 91 def _receiver_match(self, requested_sender_id, requested_receiver_id, 92 sender_id, receiver_id): 93 return bool(requested_sender_id == sender_id and requested_receiver_id == receiver_id) 94 95 def send(self, sender, **named): 96 """ 97 Send signal from sender to all connected receivers. 196 98 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: 303
