Ticket #6814: signals_8156-2.diff
File signals_8156-2.diff, 68.0 KB (added by , 16 years ago) |
---|
-
django/test/client.py
11 11 from django.core.handlers.base import BaseHandler 12 12 from django.core.handlers.wsgi import WSGIRequest 13 13 from django.core.signals import got_request_exception 14 from django.dispatch import dispatcher15 14 from django.http import SimpleCookie, HttpRequest 16 15 from django.template import TemplateDoesNotExist 17 16 from django.test import signals … … 59 58 if self._request_middleware is None: 60 59 self.load_middleware() 61 60 62 dispatcher.send(signal=signals.request_started)61 signals.request_started.send(sender=self.__class__) 63 62 try: 64 63 request = WSGIRequest(environ) 65 64 response = self.get_response(request) … … 69 68 response = middleware_method(request, response) 70 69 response = self.apply_response_fixes(request, response) 71 70 finally: 72 dispatcher.send(signal=signals.request_finished)71 signals.request_finished.send(sender=self.__class__) 73 72 74 73 return response 75 74 76 def store_rendered_templates(store, signal, sender, template, context ):75 def store_rendered_templates(store, signal, sender, template, context, **kwargs): 77 76 """ 78 77 Stores templates and contexts that are rendered. 79 78 """ … … 160 159 self.cookies = SimpleCookie() 161 160 self.exc_info = None 162 161 163 def store_exc_info(self, * args, **kwargs):162 def store_exc_info(self, **kwargs): 164 163 """ 165 164 Stores exceptions when they are generated by a view. 166 165 """ … … 202 201 # callback function. 203 202 data = {} 204 203 on_template_render = curry(store_rendered_templates, data) 205 dispatcher.connect(on_template_render, signal=signals.template_rendered)204 signals.template_rendered.connect(on_template_render) 206 205 207 206 # Capture exceptions created by the handler. 208 dispatcher.connect(self.store_exc_info, signal=got_request_exception)207 got_request_exception.connect(self.store_exc_info) 209 208 210 209 try: 211 210 response = self.handler(environ) -
django/test/signals.py
1 template_rendered = object() 2 No newline at end of file 1 from django.dispatch.dispatcher import Signal 2 3 template_rendered = Signal(providing_args=["template", "context"]) -
django/test/utils.py
3 3 from django.db import connection, get_creation_module 4 4 from django.core import mail 5 5 from django.core.management import call_command 6 from django.dispatch import dispatcher7 6 from django.test import signals 8 7 from django.template import Template 9 8 from django.utils.translation import deactivate … … 17 16 An instrumented Template render method, providing a signal 18 17 that can be intercepted by the test system Client 19 18 """ 20 dispatcher.send(signal=signals.template_rendered,sender=self, template=self, context=context)19 signals.template_rendered.send(sender=self, template=self, context=context) 21 20 return self.nodelist.render(context) 22 21 23 22 class TestSMTPConnection(object): -
django/db/models/sql/query.py
11 11 12 12 from django.utils.tree import Node 13 13 from django.utils.datastructures import SortedDict 14 from django.dispatch import dispatcher15 14 from django.db import connection 16 15 from django.db.models import signals 17 16 from django.db.models.fields import FieldDoesNotExist … … 1670 1669 sentinel): 1671 1670 yield [r[:-trim] for r in rows] 1672 1671 1673 def setup_join_cache(sender ):1672 def setup_join_cache(sender, **kwargs): 1674 1673 """ 1675 1674 The information needed to join between model fields is something that is 1676 1675 invariant over the life of the model, so we cache it in the model's Options … … 1680 1679 """ 1681 1680 sender._meta._join_cache = {} 1682 1681 1683 dispatcher.connect(setup_join_cache, signal=signals.class_prepared)1682 signals.class_prepared.connect(setup_join_cache) 1684 1683 -
django/db/models/base.py
19 19 from django.db import connection, transaction 20 20 from django.db.models import signals 21 21 from django.db.models.loading import register_models, get_model 22 from django.dispatch import dispatcher23 22 from django.utils.functional import curry 24 23 from django.utils.encoding import smart_str, force_unicode, smart_unicode 25 24 from django.core.files.move import file_move_safe … … 161 160 if hasattr(cls, 'get_absolute_url'): 162 161 cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url) 163 162 164 dispatcher.send(signal=signals.class_prepared,sender=cls)163 signals.class_prepared.send(sender=cls) 165 164 166 165 167 166 class Model(object): 168 167 __metaclass__ = ModelBase 169 168 170 169 def __init__(self, *args, **kwargs): 171 dispatcher.send(signal=signals.pre_init,sender=self.__class__, args=args, kwargs=kwargs)170 signals.pre_init.send(sender=self.__class__, args=args, kwargs=kwargs) 172 171 173 172 # There is a rather weird disparity here; if kwargs, it's set, then args 174 173 # overrides it. It should be one or the other; don't duplicate the work … … 237 236 pass 238 237 if kwargs: 239 238 raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 240 dispatcher.send(signal=signals.post_init,sender=self.__class__, instance=self)239 signals.post_init.send(sender=self.__class__, instance=self) 241 240 242 241 def __repr__(self): 243 242 return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self))) … … 286 285 cls = self.__class__ 287 286 meta = self._meta 288 287 signal = True 289 dispatcher.send(signal=signals.pre_save, sender=self.__class__, 290 instance=self, raw=raw) 288 signals.pre_save.send(sender=self.__class__, instance=self, raw=raw) 291 289 else: 292 290 meta = cls._meta 293 291 signal = False … … 349 347 transaction.commit_unless_managed() 350 348 351 349 if signal: 352 dispatcher.send(signal=signals.post_save, sender=self.__class__,353 instance=self,created=(not record_exists), raw=raw)350 signals.post_save.send(sender=self.__class__, instance=self, 351 created=(not record_exists), raw=raw) 354 352 355 353 save_base.alters_data = True 356 354 -
django/db/models/manager.py
1 1 import copy 2 2 3 3 from django.db.models.query import QuerySet, EmptyQuerySet, insert_query 4 from django.dispatch import dispatcher5 4 from django.db.models import signals 6 5 from django.db.models.fields import FieldDoesNotExist 7 6 8 def ensure_default_manager(sender ):7 def ensure_default_manager(sender, **kwargs): 9 8 cls = sender 10 9 if not getattr(cls, '_default_manager', None) and not cls._meta.abstract: 11 10 # Create the default manager, if needed. … … 16 15 pass 17 16 cls.add_to_class('objects', Manager()) 18 17 19 dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)18 signals.class_prepared.connect(ensure_default_manager) 20 19 21 20 class Manager(object): 22 21 # Tracks each time a Manager instance is created. Used to retain order. -
django/db/models/manipulators.py
2 2 from django import oldforms 3 3 from django.core import validators 4 4 from django.db.models.fields import FileField, AutoField 5 from django.dispatch import dispatcher6 5 from django.db.models import signals 7 6 from django.utils.functional import curry 8 7 from django.utils.datastructures import DotExpandedDict … … 11 10 from django.utils.translation import ugettext as _ 12 11 from django.utils import datetime_safe 13 12 14 def add_manipulators(sender ):13 def add_manipulators(sender, **kwargs): 15 14 cls = sender 16 15 cls.add_to_class('AddManipulator', AutomaticAddManipulator) 17 16 cls.add_to_class('ChangeManipulator', AutomaticChangeManipulator) 18 17 19 dispatcher.connect(add_manipulators, signal=signals.class_prepared)18 signals.class_prepared.connect(add_manipulators) 20 19 21 20 class ManipulatorDescriptor(object): 22 21 # This class provides the functionality that makes the default model -
django/db/models/fields/__init__.py
10 10 from django.db import connection, get_creation_module 11 11 from django.db.models import signals 12 12 from django.db.models.query_utils import QueryWrapper 13 from django.dispatch import dispatcher14 13 from django.conf import settings 15 14 from django.core import validators 16 15 from django import oldforms … … 824 823 setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self)) 825 824 setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self)) 826 825 setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save)) 827 dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)826 signals.post_delete.connect(self.delete_file, sender=cls) 828 827 829 def delete_file(self, instance ):828 def delete_file(self, instance, **kwargs): 830 829 if getattr(instance, self.attname): 831 830 file_name = getattr(instance, 'get_%s_filename' % self.name)() 832 831 # If the file exists and no other object of this type references it, -
django/db/models/fields/related.py
9 9 from django.core import validators 10 10 from django import oldforms 11 11 from django import forms 12 from django.dispatch import dispatcher13 12 14 13 try: 15 14 set … … 74 73 value = (cls, field, operation) 75 74 pending_lookups.setdefault(key, []).append(value) 76 75 77 def do_pending_lookups(sender ):76 def do_pending_lookups(sender, **kwargs): 78 77 """ 79 78 Handle any pending relations to the sending model. Sent from class_prepared. 80 79 """ … … 82 81 for cls, field, operation in pending_lookups.pop(key, []): 83 82 operation(field, sender, cls) 84 83 85 dispatcher.connect(do_pending_lookups, signal=signals.class_prepared)84 signals.class_prepared.connect(do_pending_lookups) 86 85 87 86 def manipulator_valid_rel_key(f, self, field_data, all_data): 88 87 "Validates that the value is a valid foreign key" -
django/db/models/signals.py
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(providing_args=["class"]) 5 4 6 pre_ save = object()7 post_ save = object()5 pre_init = Signal(providing_args=["instance", "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=["class", "app", "created_models", "verbosity", "interactive"]) -
django/db/models/query.py
8 8 from django.db.models.fields import DateField 9 9 from django.db.models.query_utils import Q, select_related_descend 10 10 from django.db.models import signals, sql 11 from django.dispatch import dispatcher12 11 from django.utils.datastructures import SortedDict 13 12 14 13 … … 827 826 828 827 # Pre-notify all instances to be deleted. 829 828 for pk_val, instance in items: 830 dispatcher.send(signal=signals.pre_delete, sender=cls, 831 instance=instance) 829 signals.pre_delete.send(sender=cls, instance=instance) 832 830 833 831 pk_list = [pk for pk,instance in items] 834 832 del_query = sql.DeleteQuery(cls, connection) … … 862 860 if field.rel and field.null and field.rel.to in seen_objs: 863 861 setattr(instance, field.attname, None) 864 862 865 dispatcher.send(signal=signals.post_delete, sender=cls, 866 instance=instance) 863 signals.post_delete.send(sender=cls, instance=instance) 867 864 setattr(instance, cls._meta.pk.attname, None) 868 865 869 866 transaction.commit_unless_managed() -
django/db/__init__.py
2 2 from django.conf import settings 3 3 from django.core import signals 4 4 from django.core.exceptions import ImproperlyConfigured 5 from django.dispatch import dispatcher6 5 from django.utils.functional import curry 7 6 8 7 __all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError') … … 58 57 59 58 # Register an event that closes the database connection 60 59 # when a Django request is finished. 61 dispatcher.connect(connection.close, signal=signals.request_finished) 60 def close_connection(**kwargs): 61 connection.close() 62 signals.request_finished.connect(close_connection) 62 63 63 64 # Register an event that resets connection.queries 64 65 # when a Django request is started. 65 def reset_queries( ):66 def reset_queries(**kwargs): 66 67 connection.queries = [] 67 dispatcher.connect(reset_queries, signal=signals.request_started)68 signals.request_started.connect(reset_queries) 68 69 69 70 # Register an event that rolls back the connection 70 71 # when a Django request has an exception. 71 def _rollback_on_exception( ):72 def _rollback_on_exception(**kwargs): 72 73 from django.db import transaction 73 74 transaction.rollback_unless_managed() 74 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)75 signals.got_request_exception.connect(_rollback_on_exception) -
django/core/signals.py
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/core/handlers/wsgi.py
9 9 from django.core import signals 10 10 from django.core.handlers import base 11 11 from django.core.urlresolvers import set_script_prefix 12 from django.dispatch import dispatcher13 12 from django.utils import datastructures 14 13 from django.utils.encoding import force_unicode 15 14 … … 207 206 self.initLock.release() 208 207 209 208 set_script_prefix(base.get_script_name(environ)) 210 dispatcher.send(signal=signals.request_started)209 signals.request_started.send(sender=self.__class__) 211 210 try: 212 211 try: 213 212 request = self.request_class(environ) … … 221 220 response = middleware_method(request, response) 222 221 response = self.apply_response_fixes(request, response) 223 222 finally: 224 dispatcher.send(signal=signals.request_finished)223 signals.request_finished.send(sender=self.__class__) 225 224 226 225 try: 227 226 status_text = STATUS_CODE_TEXT[response.status_code] -
django/core/handlers/base.py
2 2 3 3 from django import http 4 4 from django.core import signals 5 from django.dispatch import dispatcher6 5 from django.utils.encoding import force_unicode 7 6 8 7 class BaseHandler(object): … … 122 121 except: # Handle everything else, including SuspiciousOperation, etc. 123 122 # Get the exception info now, in case another exception is thrown later. 124 123 exc_info = sys.exc_info() 125 receivers = dispatcher.send(signal=signals.got_request_exception, request=request)124 receivers = signals.got_request_exception.send(sender=self.__class__, request=request) 126 125 return self.handle_uncaught_exception(request, resolver, exc_info) 127 126 128 127 def handle_uncaught_exception(self, request, resolver, exc_info): -
django/core/handlers/modpython.py
5 5 from django.core import signals 6 6 from django.core.handlers.base import BaseHandler 7 7 from django.core.urlresolvers import set_script_prefix 8 from django.dispatch import dispatcher9 8 from django.utils import datastructures 10 9 from django.utils.encoding import force_unicode, smart_str 11 10 … … 174 173 self.load_middleware() 175 174 176 175 set_script_prefix(req.get_options().get('django.root', '')) 177 dispatcher.send(signal=signals.request_started)176 signals.request_started.send(sender=self.__class__) 178 177 try: 179 178 try: 180 179 request = self.request_class(req) … … 188 187 response = middleware_method(request, response) 189 188 response = self.apply_response_fixes(request, response) 190 189 finally: 191 dispatcher.send(signal=signals.request_finished)190 signals.request_finished.send(sender=self.__class__) 192 191 193 192 # Convert our custom HttpResponse object back into the mod_python req. 194 193 req.content_type = response['Content-Type'] -
django/core/management/commands/flush.py
15 15 def handle_noargs(self, **options): 16 16 from django.conf import settings 17 17 from django.db import connection, transaction, models 18 from django.dispatch import dispatcher19 18 from django.core.management.sql import sql_flush, emit_post_sync_signal 20 19 21 20 verbosity = int(options.get('verbosity', 1)) -
django/core/management/sql.py
492 492 app_name = app.__name__.split('.')[-2] 493 493 if verbosity >= 2: 494 494 print "Running post-sync handlers for application", app_name 495 dispatcher.send(signal=models.signals.post_syncdb, sender=app,496 app=app, created_models=created_models,497 verbosity=verbosity,interactive=interactive)495 models.signals.post_syncdb.send(sender=app, app=app, 496 created_models=created_models, verbosity=verbosity, 497 interactive=interactive) -
django/dispatch/errors.py
1 """Error types for dispatcher mechanism2 """3 4 class DispatcherError(Exception):5 """Base class for all Dispatcher errors"""6 class DispatcherKeyError(KeyError, DispatcherError):7 """Error raised when unknown (sender,signal) set specified"""8 class DispatcherTypeError(TypeError, DispatcherError):9 """Error raised when inappropriate signal-type specified (None)"""10 -
django/dispatch/robust.py
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
1 1 """Multi-consumer multi-producer dispatching mechanism 2 3 Originally based on pydispatch (BSD) http://pypi.python.org/pypi/PyDispatcher/2.0.1 4 See license.txt for original license. 5 6 Heavily modified for Django's purposes. 2 7 """ 3 __version__ = "1.0.0"4 __author__ = "Patrick K. O'Brien"5 __license__ = "BSD-style, see license.txt for details"6 -
django/dispatch/robustapply.py
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.py
1 """Multiple-producer-multiple-consumer signal-dispatching2 3 dispatcher is the core of the PyDispatcher system,4 providing the primary API and the core logic for the5 system.6 7 Module attributes of note:8 9 Any -- Singleton used to signal either "Any Sender" or10 "Any Signal". See documentation of the _Any class.11 Anonymous -- Singleton used to signal "Anonymous Sender"12 See documentation of the _Anonymous class.13 14 Internal attributes:15 WEAKREF_TYPES -- tuple of types/classes which represent16 weak references to receivers, and thus must be de-17 referenced on retrieval to retrieve the callable18 object19 connections -- { senderkey (id) : { signal : [receivers...]}}20 senders -- { senderkey (id) : weakref(sender) }21 used for cleaning up sender references on sender22 deletion23 sendersBack -- { receiverkey (id) : [senderkey (id)...] }24 used for cleaning up receiver references on receiver25 deletion, (considerably speeds up the cleanup process26 vs. the original code.)27 """28 1 import weakref 29 from django.dispatch import saferef, robustapply, errors 2 try: 3 set 4 except NameError: 5 from sets import Set as set # Python 2.3 fallback 30 6 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] 7 from django.dispatch import saferef 34 8 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 given46 Any should react to all senders/signals, not just47 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 sender55 of a message is not specified (as distinct from being56 "any sender"). Registering callbacks for Anonymous57 will only receive messages sent without senders. Sending58 with anonymous will only send messages to those receivers59 registered for Any or Anonymous.60 61 Note:62 The default sender for connect is Any, while the63 default sender for send is Anonymous. This has64 the effect that if you do not specify any senders65 in either function then all messages are routed66 as though there was a single sender (Anonymous)67 being used everywhere.68 """69 Anonymous = _Anonymous()70 71 9 WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref) 72 10 73 connections = {} 74 senders = {} 75 sendersBack = {} 11 def _make_id(target): 12 if hasattr(target, 'im_func'): 13 return (id(target.im_self), id(target.im_func)) 14 return id(target) 76 15 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). 16 class Signal(object): 17 """Base class for all signals 88 18 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 19 Internal attributes: 20 receivers -- { receriverkey (id) : weakref(receiver) } 21 """ 104 22 105 if Any, receiver will receive any signal from the 106 indicated sender (which might also be Any, but is not 107 necessarily Any). 23 def __init__(self, providing_args=[]): 24 """providing_args -- A list of the arguments this signal can pass along in 25 a send() call. 26 """ 27 self.registered_uids = set() 28 self.receivers = [] 29 self.providing_args = set(providing_args) 30 31 def connect(self, receiver, sender=None, weak=True): 32 """Connect receiver to sender for signal 33 34 receiver -- a function or an instance method which is to 35 receive signals. Receivers must be 36 hashable objects. 37 38 if weak is True, then receiver must be weak-referencable 39 (more precisely saferef.safeRef() must be able to create 40 a reference to the receiver). 108 41 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 42 Receivers must be able to accept keyword arguments. 43 44 If receivers have a dispatch_uid attribute, the receiver will 45 not be added if another receiver already exists with that 46 dispatch_uid. 47 48 sender -- the sender to which the receiver should respond 49 Must either be of type Signal, or None to receive events 50 from any sender. 51 52 weak -- whether to use weak references to the receiver 53 By default, the module will attempt to use weak 54 references to the receiver objects. If this parameter 55 is false, then strong references will be used. 113 56 114 if Any, receiver will receive the indicated signals 115 from any sender. 57 returns None 58 """ 59 from django.conf import settings 116 60 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. 61 if settings.DEBUG: 62 import inspect 63 assert inspect.getargspec(receiver)[2] is not None, \ 64 "Signal receivers should accept keyword arguments (**kwargs)." 122 65 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. 66 uid = getattr(receiver, 'dispatch_uid', None) 67 if uid and uid in self.registered_uids: 68 return 127 69 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) 70 lookup_key = (_make_id(receiver), _make_id(sender)) 137 71 138 signals = connections.setdefault(senderkey, {}) 72 if weak: 73 receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver) 139 74 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 152 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 75 for r_key, _ in self.receivers: 76 if r_key == lookup_key: 77 break 78 else: 79 self.receivers.append((lookup_key, receiver)) 80 if uid: 81 self.registered_uids.add(uid) 169 82 170 receivers.append(receiver) 83 def disconnect(self, receiver, sender=None, weak=True): 84 """Disconnect receiver from sender for signal 85 86 receiver -- the registered receiver to disconnect 87 sender -- the registered sender to disconnect 88 weak -- the weakref state to disconnect 89 90 disconnect reverses the process of connect. 91 92 If weak references are used, disconnect need not be called. 93 The receiver will be remove from dispatch automatically. 94 95 returns None 96 """ 97 lookup_key = (_make_id(receiver), _make_id(sender)) 171 98 99 uid = getattr(receiver, 'dispatch_uid', None) 172 100 101 for idx, (r_key, _) in enumerate(self.receivers): 102 if r_key == lookup_key: 103 del self.receivers[idx] 104 if uid: 105 self.registered_uids.remove(uid) 106 107 def send(self, sender, **named): 108 """Send signal from sender to all connected receivers. 109 110 sender -- the sender of the signal 111 Either a specific object or None. 112 113 named -- named arguments which will be passed to receivers. 173 114 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. 115 Returns a list of tuple pairs [(receiver, response), ... ]. 196 116 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) 117 If any receiver raises an error, the error propagates back 118 through send, terminating the dispatch loop, so it is quite 119 possible to not have all receivers called if a raises an 120 error. 121 """ 228 122 229 def getReceivers(sender=Any, signal=Any): 230 """Get list of receivers from global tables 123 responses = [] 124 if not self.receivers: 125 return responses 231 126 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. 127 for receiver in self._live_receivers(_make_id(sender)): 128 response = receiver(signal=self, sender=sender, **named) 129 responses.append((receiver, response)) 130 return responses 235 131 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. 132 def send_robust(self, sender, **named): 133 """Send signal from sender to all connected receivers catching errors 242 134 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 [] 135 sender -- the sender of the signal 136 Can be any python object (normally one registered with 137 a connect if you actually want something to occur). 251 138 252 def liveReceivers(receivers): 253 """Filter sequence of receivers to get resolved, live receivers 139 named -- named arguments which will be passed to receivers. 140 These arguments must be a subset of the argument names 141 defined in providing_args, or a DispatcherTypeError will be 142 raised. 254 143 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 144 Return a list of tuple pairs [(receiver, response), ... ], 145 may raise DispatcherKeyError 268 146 147 if any receiver raises an error (specifically any subclass of Exception), 148 the error instance is returned as the result for that receiver. 149 """ 269 150 151 responses = [] 152 if not self.receivers: 153 return responses 270 154 271 def getAllReceivers(sender=Any, signal=Any): 272 """Get list of all receivers from global tables 155 # Call each receiver with whatever arguments it can accept. 156 # Return a list of tuple pairs [(receiver, response), ... ]. 157 for receiver in self._live_receivers(_make_id(sender)): 158 try: 159 response = receiver(signal=self, sender=sender, **named) 160 except Exception, err: 161 responses.append((receiver, err)) 162 else: 163 responses.append((receiver, response)) 164 return responses 273 165 274 This gets all dereferenced receivers which should receive275 the given signal from sender, each receiver should276 be produced only once by the resulting generator277 """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 166 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 try: 304 if not receiver in receivers: 167 168 def _live_receivers(self, senderkey): 169 """Filter sequence of receivers to get resolved, live receivers 170 171 This checks for weak references 172 and resolves them, then returning only live 173 receivers. 174 """ 175 none_senderkey = _make_id(None) 176 177 for (receiverkey, r_senderkey), receiver in self.receivers: 178 if r_senderkey == none_senderkey or r_senderkey == senderkey: 305 179 if isinstance(receiver, WEAKREF_TYPES): 180 # Dereference the weak reference. 306 181 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 182 if receiver is not None: 183 yield receiver 184 else: 185 yield receiver 316 186 317 def send(signal=Any, sender=Anonymous, *arguments, **named):318 """Send signal from sender to all connected receivers.319 320 signal -- (hashable) signal value, see connect for details187 def _remove_receiver(self, receiver): 188 """Remove dead receivers from connections.""" 189 190 uid = getattr(receiver, 'dispatch_uid', None) 321 191 322 sender -- the sender of the signal 323 324 if Any, only receivers registered for Any will receive 325 the message. 192 to_remove = [] 193 for key, connected_receiver in self.receivers: 194 if connected_receiver == receiver: 195 to_remove.append(key) 196 for key in to_remove: 197 for idx, (r_key, _) in enumerate(self.receivers): 198 if r_key == key: 199 del self.receivers[idx] 200 if uid: 201 self.registered_uids.remove(uid) 326 202 327 if Anonymous, only receivers registered to receive 328 messages from Anonymous or Any will receive the message 203 204 def connect(receiver, signal, sender=None, weak=True): 205 """For backward compatibility only. See Signal.connect() 206 """ 207 return signal.connect(receiver, sender, weak) 329 208 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. 209 def disconnect(receiver, signal, sender=None, weak=True): 210 """For backward compatibility only. See Signal.disconnect() 350 211 """ 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 212 signal.disconnect(receiver, sender, weak) 364 213 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. 214 def send(signal, sender=None, **named): 215 """For backward compatibility only. See Signal.send() 373 216 """ 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 385 217 return signal.send(sender=sender, **named) 386 218 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. 424 try: 425 signals = connections[senderkey] 426 except KeyError: 427 pass 428 else: 429 del signals[signal] 430 if not signals: 431 # No more signal connections. Therefore, remove the sender. 432 _removeSender(senderkey) 433 434 def _removeSender(senderkey): 435 """Remove senderkey from connections.""" 436 _removeBackrefs(senderkey) 437 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 219 def sendExact(signal, sender, **named ): 220 """This function is deprecated, as it now has the same 221 meaning as send. 457 222 """ 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 479 480 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: 486 try: 487 receivers_list.remove(senderkey) 488 except: 489 break 490 if not receivers_list: 491 try: 492 del sendersBack[ receiverkey ] 493 except KeyError: 494 pass 495 return True 223 return signal.send(sender=sender, **named) -
django/contrib/sites/management.py
2 2 Creates the default Site object. 3 3 """ 4 4 5 from django.dispatch import dispatcher6 5 from django.db.models import signals 7 6 from django.contrib.sites.models import Site 8 7 from django.contrib.sites import models as site_app 9 8 10 def create_default_site(app, created_models, verbosity ):9 def create_default_site(app, created_models, verbosity, **kwargs): 11 10 if Site in created_models: 12 11 if verbosity >= 2: 13 12 print "Creating example.com Site object" … … 15 14 s.save() 16 15 Site.objects.clear_cache() 17 16 18 dispatcher.connect(create_default_site, sender=site_app, signal=signals.post_syncdb)17 signals.post_syncdb.connect(create_default_site, sender=site_app) -
django/contrib/contenttypes/management.py
1 1 from django.contrib.contenttypes.models import ContentType 2 from django.dispatch import dispatcher3 2 from django.db.models import get_apps, get_models, signals 4 3 from django.utils.encoding import smart_unicode 5 4 6 def update_contenttypes(app, created_models, verbosity=2 ):5 def update_contenttypes(app, created_models, verbosity=2, **kwargs): 7 6 """ 8 7 Creates content types for models in the given app, removing any model 9 8 entries that no longer have a matching model class. … … 37 36 for app in get_apps(): 38 37 update_contenttypes(app, None, verbosity) 39 38 40 dispatcher.connect(update_contenttypes, signal=signals.post_syncdb)39 signals.post_syncdb.connect(update_contenttypes) 41 40 42 41 if __name__ == "__main__": 43 42 update_all_contenttypes() -
django/contrib/contenttypes/generic.py
8 8 from django.db.models import signals 9 9 from django.db.models.fields.related import RelatedField, Field, ManyToManyRel 10 10 from django.db.models.loading import get_model 11 from django.dispatch import dispatcher12 11 from django.utils.functional import curry 13 12 14 13 class GenericForeignKey(object): … … 29 28 self.cache_attr = "_%s_cache" % name 30 29 31 30 # For some reason I don't totally understand, using weakrefs here doesn't work. 32 dispatcher.connect(self.instance_pre_init, signal=signals.pre_init, sender=cls, weak=False)31 signals.pre_init.connect(self.instance_pre_init, sender=cls, weak=False) 33 32 34 33 # Connect myself as the descriptor for this field 35 34 setattr(cls, name, self) 36 35 37 def instance_pre_init(self, signal, sender, args, kwargs ):36 def instance_pre_init(self, signal, sender, args, kwargs, **_kwargs): 38 37 """ 39 38 Handles initializing an object with the generic FK instaed of 40 39 content-type/object-id fields. -
django/contrib/auth/management/__init__.py
2 2 Creates permissions for all installed apps that need permissions. 3 3 """ 4 4 5 from django.dispatch import dispatcher6 5 from django.db.models import get_models, signals 7 6 from django.contrib.auth import models as auth_app 8 7 … … 16 15 perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw))) 17 16 return perms + list(opts.permissions) 18 17 19 def create_permissions(app, created_models, verbosity ):18 def create_permissions(app, created_models, verbosity, **kwargs): 20 19 from django.contrib.contenttypes.models import ContentType 21 20 from django.contrib.auth.models import Permission 22 21 app_models = get_models(app) … … 29 28 defaults={'name': name, 'content_type': ctype}) 30 29 if created and verbosity >= 2: 31 30 print "Adding permission '%s'" % p 31 create_permissions.dispatch_uid = "django.contrib.auth.management.create_permissions" 32 32 33 33 def create_superuser(app, created_models, verbosity, **kwargs): 34 34 from django.contrib.auth.models import User … … 44 44 if confirm == 'yes': 45 45 call_command("createsuperuser", interactive=True) 46 46 break 47 create_superuser.dispatch_uid = "django.contrib.auth.management.create_superuser" 47 48 48 if 'create_permissions' not in [i.__name__ for i in dispatcher.getAllReceivers(signal=signals.post_syncdb)]: 49 dispatcher.connect(create_permissions, signal=signals.post_syncdb) 50 if 'create_superuser' not in [i.__name__ for i in dispatcher.getAllReceivers(signal=signals.post_syncdb, sender=auth_app)]: 51 dispatcher.connect(create_superuser, sender=auth_app, signal=signals.post_syncdb) 52 No newline at end of file 49 signals.post_syncdb.connect(create_permissions) 50 signals.post_syncdb.connect(create_superuser, sender=auth_app) 51 No newline at end of file -
tests/modeltests/signals/models.py
3 3 """ 4 4 5 5 from django.db import models 6 from django.dispatch import dispatcher7 6 8 7 class Person(models.Model): 9 8 first_name = models.CharField(max_length=20) … … 12 11 def __unicode__(self): 13 12 return u"%s %s" % (self.first_name, self.last_name) 14 13 15 16 def pre_save_nokwargs_test(sender, instance): 17 print 'pre_save_nokwargs signal' 18 19 def post_save_nokwargs_test(sender, instance): 20 print 'post_save_nokwargs signal' 21 22 def pre_save_test(sender, instance, **kwargs): 14 def pre_save_test(signal, sender, instance, **kwargs): 23 15 print 'pre_save signal,', instance 24 16 if kwargs.get('raw'): 25 17 print 'Is raw' 26 18 27 def post_save_test(s ender, instance, **kwargs):19 def post_save_test(signal, sender, instance, **kwargs): 28 20 print 'post_save signal,', instance 29 21 if 'created' in kwargs: 30 22 if kwargs['created']: … … 34 26 if kwargs.get('raw'): 35 27 print 'Is raw' 36 28 37 def pre_delete_test(s ender, instance, **kwargs):29 def pre_delete_test(signal, sender, instance, **kwargs): 38 30 print 'pre_delete signal,', instance 39 31 print 'instance.id is not None: %s' % (instance.id != None) 40 32 41 def post_delete_test(s ender, instance, **kwargs):33 def post_delete_test(signal, sender, instance, **kwargs): 42 34 print 'post_delete signal,', instance 43 35 print 'instance.id is None: %s' % (instance.id == None) 44 36 45 37 __test__ = {'API_TESTS':""" 46 >>> dispatcher.connect(pre_save_nokwargs_test, signal=models.signals.pre_save) 47 >>> dispatcher.connect(post_save_nokwargs_test, signal=models.signals.post_save) 48 >>> dispatcher.connect(pre_save_test, signal=models.signals.pre_save) 49 >>> dispatcher.connect(post_save_test, signal=models.signals.post_save) 50 >>> dispatcher.connect(pre_delete_test, signal=models.signals.pre_delete) 51 >>> dispatcher.connect(post_delete_test, signal=models.signals.post_delete) 38 >>> models.signals.pre_save.connect(pre_save_test) 39 >>> models.signals.post_save.connect(post_save_test) 40 >>> models.signals.pre_delete.connect(pre_delete_test) 41 >>> models.signals.post_delete.connect(post_delete_test) 52 42 53 43 >>> p1 = Person(first_name='John', last_name='Smith') 54 44 >>> p1.save() 55 pre_save_nokwargs signal56 45 pre_save signal, John Smith 57 post_save_nokwargs signal58 46 post_save signal, John Smith 59 47 Is created 60 48 61 49 >>> p1.first_name = 'Tom' 62 50 >>> p1.save() 63 pre_save_nokwargs signal64 51 pre_save signal, Tom Smith 65 post_save_nokwargs signal66 52 post_save signal, Tom Smith 67 53 Is updated 68 54 69 55 # Calling an internal method purely so that we can trigger a "raw" save. 70 56 >>> p1.save_base(raw=True) 71 pre_save_nokwargs signal72 57 pre_save signal, Tom Smith 73 58 Is raw 74 post_save_nokwargs signal75 59 post_save signal, Tom Smith 76 60 Is updated 77 61 Is raw … … 85 69 >>> p2 = Person(first_name='James', last_name='Jones') 86 70 >>> p2.id = 99999 87 71 >>> p2.save() 88 pre_save_nokwargs signal89 72 pre_save signal, James Jones 90 post_save_nokwargs signal91 73 post_save signal, James Jones 92 74 Is created 93 75 94 76 >>> p2.id = 99998 95 77 >>> p2.save() 96 pre_save_nokwargs signal97 78 pre_save signal, James Jones 98 post_save_nokwargs signal99 79 post_save signal, James Jones 100 80 Is created 101 81 … … 108 88 >>> Person.objects.all() 109 89 [<Person: James Jones>] 110 90 111 >>> dispatcher.disconnect(pre_save_nokwargs_test, signal=models.signals.pre_save) 112 >>> dispatcher.disconnect(post_save_nokwargs_test, signal=models.signals.post_save) 113 >>> dispatcher.disconnect(post_delete_test, signal=models.signals.post_delete) 114 >>> dispatcher.disconnect(pre_delete_test, signal=models.signals.pre_delete) 115 >>> dispatcher.disconnect(post_save_test, signal=models.signals.post_save) 116 >>> dispatcher.disconnect(pre_save_test, signal=models.signals.pre_save) 91 >>> models.signals.post_delete.disconnect(post_delete_test) 92 >>> models.signals.pre_delete.disconnect(pre_delete_test) 93 >>> models.signals.post_save.disconnect(post_save_test) 94 >>> models.signals.pre_save.disconnect(pre_save_test) 117 95 """} -
tests/regressiontests/dispatch/tests/__init__.py
2 2 Unit-tests for the dispatch project 3 3 """ 4 4 5 from test_dispatcher import *6 from test_robustapply import *7 5 from test_saferef import * 6 from test_dispatcher import * 7 No newline at end of file -
tests/regressiontests/dispatch/tests/test_robustapply.py
1 from django.dispatch.robustapply import *2 3 import unittest4 5 def noArgument():6 pass7 8 def oneArgument(blah):9 pass10 11 def twoArgument(blah, other):12 pass13 14 class TestCases(unittest.TestCase):15 def test01(self):16 robustApply(noArgument)17 18 def test02(self):19 self.assertRaises(TypeError, robustApply, noArgument, "this")20 21 def test03(self):22 self.assertRaises(TypeError, robustApply, oneArgument)23 24 def test04(self):25 """Raise error on duplication of a particular argument"""26 self.assertRaises(TypeError, robustApply, oneArgument, "this", blah = "that")27 28 def getSuite():29 return unittest.makeSuite(TestCases,'test')30 31 32 if __name__ == "__main__":33 unittest.main()34 -
tests/regressiontests/dispatch/tests/test_dispatcher.py
1 from django.dispatch.dispatcher import * 2 from django.dispatch import dispatcher, robust 1 from django.dispatch.dispatcher import Signal 3 2 import unittest 4 3 import copy 5 4 import sys … … 15 14 def garbage_collect(): 16 15 gc.collect() 17 16 18 def x(a):19 return a17 def receiver_1_arg(val, **kwargs): 18 return val 20 19 21 class Dummy(object):22 pass23 24 20 class Callable(object): 25 def __call__(self, a):26 return a21 def __call__(self, val, **kwargs): 22 return val 27 23 28 def a(self, a):29 return a24 def a(self, val, **kwargs): 25 return val 30 26 27 a_signal = Signal(providing_args=["val"]) 28 31 29 class DispatcherTests(unittest.TestCase): 32 30 """Test suite for dispatcher (barely started)""" 33 34 def setUp(self): 35 # track the initial state, since it's possible that others have bleed receivers in 36 garbage_collect() 37 self.sendersBack = copy.copy(dispatcher.sendersBack) 38 self.connections = copy.copy(dispatcher.connections) 39 self.senders = copy.copy(dispatcher.senders) 40 41 def _testIsClean(self): 31 32 def _testIsClean(self, signal): 42 33 """Assert that everything has been cleaned up automatically""" 43 self.assertEqual(dispatcher.sendersBack, self.sendersBack) 44 self.assertEqual(dispatcher.connections, self.connections) 45 self.assertEqual(dispatcher.senders, self.senders) 34 self.assertEqual(signal.receivers, []) 35 self.assertEqual(signal.registered_uids, set()) 36 37 # force cleanup just in case 38 signal.receivers = [] 39 signal.registered_uids = set() 46 40 47 41 def testExact(self): 48 a = Dummy() 49 signal = 'this' 50 connect(x, signal, a) 51 expected = [(x,a)] 52 result = send('this',a, a=a) 42 a_signal.connect(receiver_1_arg, sender=self) 43 expected = [(receiver_1_arg,"test")] 44 result = a_signal.send(sender=self, val="test") 53 45 self.assertEqual(result, expected) 54 disconnect(x, signal, a) 55 self.assertEqual(list(getAllReceivers(a,signal)), []) 56 self._testIsClean() 57 58 def testAnonymousSend(self): 59 a = Dummy() 60 signal = 'this' 61 connect(x, signal) 62 expected = [(x,a)] 63 result = send(signal,None, a=a) 46 a_signal.disconnect(receiver_1_arg, sender=self) 47 self._testIsClean(a_signal) 48 49 def testIgnoredSender(self): 50 a_signal.connect(receiver_1_arg) 51 expected = [(receiver_1_arg,"test")] 52 result = a_signal.send(sender=self, val="test") 64 53 self.assertEqual(result, expected) 65 disconnect(x, signal) 66 self.assertEqual(list(getAllReceivers(None,signal)), []) 67 self._testIsClean() 54 a_signal.disconnect(receiver_1_arg) 55 self._testIsClean(a_signal) 68 56 69 def testAnyRegistration(self):70 a = Dummy()71 signal = 'this'72 connect(x, signal, Any)73 expected = [(x,a)]74 result = send('this',object(), a=a)75 self.assertEqual(result, expected)76 disconnect(x, signal, Any)77 expected = []78 result = send('this',object(), a=a)79 self.assertEqual(result, expected)80 self.assertEqual(list(getAllReceivers(Any,signal)), [])81 82 self._testIsClean()83 84 def testAnyRegistration2(self):85 a = Dummy()86 signal = 'this'87 connect(x, Any, a)88 expected = [(x,a)]89 result = send('this',a, a=a)90 self.assertEqual(result, expected)91 disconnect(x, Any, a)92 self.assertEqual(list(getAllReceivers(a,Any)), [])93 self._testIsClean()94 95 57 def testGarbageCollected(self): 96 58 a = Callable() 97 b = Dummy() 98 signal = 'this' 99 connect(a.a, signal, b) 59 a_signal.connect(a.a, sender=self) 100 60 expected = [] 101 61 del a 102 62 garbage_collect() 103 result = send('this',b, a=b)63 result = a_signal.send(sender=self, val="test") 104 64 self.assertEqual(result, expected) 105 self.assertEqual(list(getAllReceivers(b,signal)), []) 106 self._testIsClean() 65 self._testIsClean(a_signal) 107 66 108 def testGarbageCollectedObj(self):109 class x:110 def __call__(self, a):111 return a112 a = Callable()113 b = Dummy()114 signal = 'this'115 connect(a, signal, b)116 expected = []117 del a118 garbage_collect()119 result = send('this',b, a=b)120 self.assertEqual(result, expected)121 self.assertEqual(list(getAllReceivers(b,signal)), [])122 self._testIsClean()123 124 125 67 def testMultipleRegistration(self): 126 68 a = Callable() 127 b = Dummy() 128 signal = 'this' 129 connect(a, signal, b) 130 connect(a, signal, b) 131 connect(a, signal, b) 132 connect(a, signal, b) 133 connect(a, signal, b) 134 connect(a, signal, b) 135 result = send('this',b, a=b) 69 a_signal.connect(a) 70 a_signal.connect(a) 71 a_signal.connect(a) 72 a_signal.connect(a) 73 a_signal.connect(a) 74 a_signal.connect(a) 75 result = a_signal.send(sender=self, val="test") 136 76 self.assertEqual(len(result), 1) 137 self.assertEqual(len( list(getAllReceivers(b,signal))), 1)77 self.assertEqual(len(a_signal.receivers), 1) 138 78 del a 139 del b140 79 del result 141 80 garbage_collect() 142 self._testIsClean() 81 self._testIsClean(a_signal) 82 83 def testUidRegistration(self): 84 def uid_based_receiver_1(**kwargs): 85 pass 86 uid_based_receiver_1.dispatch_uid = "uid" 87 88 def uid_based_receiver_2(**kwargs): 89 pass 90 uid_based_receiver_2.dispatch_uid = "uid" 91 92 a_signal.connect(uid_based_receiver_1) 93 a_signal.connect(uid_based_receiver_2) 94 self.assertEqual(len(a_signal.receivers), 1) 95 a_signal.disconnect(uid_based_receiver_1) 96 self._testIsClean(a_signal) 143 97 144 98 def testRobust(self): 145 99 """Test the sendRobust function""" 146 def fails( ):100 def fails(val, **kwargs): 147 101 raise ValueError('this') 148 a = object() 149 signal = 'this' 150 connect(fails, Any, a) 151 result = robust.sendRobust('this',a, a=a) 102 a_signal.connect(fails) 103 result = a_signal.send_robust(sender=self, val="test") 152 104 err = result[0][1] 153 105 self.assert_(isinstance(err, ValueError)) 154 106 self.assertEqual(err.args, ('this',)) 107 a_signal.disconnect(fails) 108 self._testIsClean(a_signal) 155 109 156 110 def getSuite(): 157 111 return unittest.makeSuite(DispatcherTests,'test')