Ticket #6814: signals_8220.diff
File signals_8220.diff, 67.7 KB (added by , 16 years ago) |
---|
-
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) … … 45 44 call_command("createsuperuser", interactive=True) 46 45 break 47 46 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 47 signals.post_syncdb.connect(create_permissions, 48 dispatch_uid = "django.contrib.auth.management.create_permissions") 49 signals.post_syncdb.connect(create_superuser, 50 sender=auth_app, dispatch_uid = "django.contrib.auth.management.create_superuser") -
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/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/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/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/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/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/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/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/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 … … 239 238 pass 240 239 if kwargs: 241 240 raise TypeError, "'%s' is an invalid keyword argument for this function" % kwargs.keys()[0] 242 dispatcher.send(signal=signals.post_init,sender=self.__class__, instance=self)241 signals.post_init.send(sender=self.__class__, instance=self) 243 242 244 243 def __repr__(self): 245 244 return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self))) … … 288 287 cls = self.__class__ 289 288 meta = self._meta 290 289 signal = True 291 dispatcher.send(signal=signals.pre_save, sender=self.__class__, 292 instance=self, raw=raw) 290 signals.pre_save.send(sender=self.__class__, instance=self, raw=raw) 293 291 else: 294 292 meta = cls._meta 295 293 signal = False … … 351 349 transaction.commit_unless_managed() 352 350 353 351 if signal: 354 dispatcher.send(signal=signals.post_save, sender=self.__class__,355 instance=self,created=(not record_exists), raw=raw)352 signals.post_save.send(sender=self.__class__, instance=self, 353 created=(not record_exists), raw=raw) 356 354 357 355 save_base.alters_data = True 358 356 -
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 … … 819 818 setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self)) 820 819 setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self)) 821 820 setattr(cls, 'save_%s_file' % self.name, lambda instance, filename, raw_field, save=True: instance._save_FIELD_file(self, filename, raw_field, save)) 822 dispatcher.connect(self.delete_file, signal=signals.post_delete, sender=cls)821 signals.post_delete.connect(self.delete_file, sender=cls) 823 822 824 def delete_file(self, instance ):823 def delete_file(self, instance, **kwargs): 825 824 if getattr(instance, self.attname): 826 825 file_name = getattr(instance, 'get_%s_filename' % self.name)() 827 826 # 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/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/query.py
7 7 from django.db.models.fields import DateField 8 8 from django.db.models.query_utils import Q, select_related_descend 9 9 from django.db.models import signals, sql 10 from django.dispatch import dispatcher11 10 from django.utils.datastructures import SortedDict 12 11 13 12 … … 810 809 811 810 # Pre-notify all instances to be deleted. 812 811 for pk_val, instance in items: 813 dispatcher.send(signal=signals.pre_delete, sender=cls, 814 instance=instance) 812 signals.pre_delete.send(sender=cls, instance=instance) 815 813 816 814 pk_list = [pk for pk,instance in items] 817 815 del_query = sql.DeleteQuery(cls, connection) … … 845 843 if field.rel and field.null and field.rel.to in seen_objs: 846 844 setattr(instance, field.attname, None) 847 845 848 dispatcher.send(signal=signals.post_delete, sender=cls, 849 instance=instance) 846 signals.post_delete.send(sender=cls, instance=instance) 850 847 setattr(instance, cls._meta.pk.attname, None) 851 848 852 849 transaction.commit_unless_managed() -
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/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/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/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.receivers = [] 28 self.providing_args = set(providing_args) 29 30 def connect(self, receiver, sender=None, weak=True, dispatch_uid=None): 31 """Connect receiver to sender for signal 32 33 receiver -- a function or an instance method which is to 34 receive signals. Receivers must be 35 hashable objects. 36 37 if weak is True, then receiver must be weak-referencable 38 (more precisely saferef.safeRef() must be able to create 39 a reference to the receiver). 108 40 109 Otherwise must be a hashable Python object other than 110 None (DispatcherError raised on None). 41 Receivers must be able to accept keyword arguments. 42 43 If receivers have a dispatch_uid attribute, the receiver will 44 not be added if another receiver already exists with that 45 dispatch_uid. 46 47 sender -- the sender to which the receiver should respond 48 Must either be of type Signal, or None to receive events 49 from any sender. 50 51 weak -- whether to use weak references to the receiver 52 By default, the module will attempt to use weak 53 references to the receiver objects. If this parameter 54 is false, then strong references will be used. 111 55 112 sender -- the sender to which the receiver should respond 56 dispatch_uid -- an identifier used to uniquely identify a particular 57 instance of a receiver. This will usually be a string, though it 58 may be anything hashable. 113 59 114 if Any, receiver will receive the indicated signals 115 from any sender. 60 returns None 61 """ 62 from django.conf import settings 116 63 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. 64 if settings.DEBUG: 65 import inspect 66 assert inspect.getargspec(receiver)[2] is not None, \ 67 "Signal receivers should accept keyword arguments (**kwargs)." 122 68 123 weak -- whether to use weak references to the receiver124 By default, the module will attempt to use weak125 references to the receiver objects. If this parameter126 is false, then strong references will be used.69 if dispatch_uid: 70 lookup_key = (dispatch_uid, _make_id(sender)) 71 else: 72 lookup_key = (_make_id(receiver), _make_id(sender)) 127 73 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) 74 if weak: 75 receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver) 137 76 138 signals = connections.setdefault(senderkey, {}) 77 for r_key, _ in self.receivers: 78 if r_key == lookup_key: 79 break 80 else: 81 self.receivers.append((lookup_key, receiver)) 139 82 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 83 def disconnect(self, receiver=None, sender=None, weak=True, dispatch_uid=None): 84 """Disconnect receiver from sender for signal 85 86 receiver -- the registered receiver to disconnect. May be none if 87 dispatch_uid is specified. 88 sender -- the registered sender to disconnect 89 weak -- the weakref state to disconnect 90 dispatch_uid -- the unique identifier of the receiver to disconnect 91 92 disconnect reverses the process of connect. 93 94 If weak references are used, disconnect need not be called. 95 The receiver will be remove from dispatch automatically. 96 97 returns None 98 """ 152 99 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 100 if dispatch_uid: 101 lookup_key = (dispatch_uid, _make_id(sender)) 102 else: 103 lookup_key = (_make_id(receiver), _make_id(sender)) 169 104 170 receivers.append(receiver) 105 for idx, (r_key, _) in enumerate(self.receivers): 106 if r_key == lookup_key: 107 del self.receivers[idx] 108 109 def send(self, sender, **named): 110 """Send signal from sender to all connected receivers. 111 112 sender -- the sender of the signal 113 Either a specific object or None. 114 115 named -- named arguments which will be passed to receivers. 171 116 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. 117 Returns a list of tuple pairs [(receiver, response), ... ]. 196 118 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) 119 If any receiver raises an error, the error propagates back 120 through send, terminating the dispatch loop, so it is quite 121 possible to not have all receivers called if a raises an 122 error. 123 """ 228 124 229 def getReceivers(sender=Any, signal=Any): 230 """Get list of receivers from global tables 125 responses = [] 126 if not self.receivers: 127 return responses 231 128 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. 129 for receiver in self._live_receivers(_make_id(sender)): 130 response = receiver(signal=self, sender=sender, **named) 131 responses.append((receiver, response)) 132 return responses 235 133 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. 134 def send_robust(self, sender, **named): 135 """Send signal from sender to all connected receivers catching errors 242 136 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 [] 137 sender -- the sender of the signal 138 Can be any python object (normally one registered with 139 a connect if you actually want something to occur). 251 140 252 def liveReceivers(receivers): 253 """Filter sequence of receivers to get resolved, live receivers 141 named -- named arguments which will be passed to receivers. 142 These arguments must be a subset of the argument names 143 defined in providing_args, or a DispatcherTypeError will be 144 raised. 254 145 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 146 Return a list of tuple pairs [(receiver, response), ... ], 147 may raise DispatcherKeyError 268 148 149 if any receiver raises an error (specifically any subclass of Exception), 150 the error instance is returned as the result for that receiver. 151 """ 269 152 153 responses = [] 154 if not self.receivers: 155 return responses 270 156 271 def getAllReceivers(sender=Any, signal=Any): 272 """Get list of all receivers from global tables 157 # Call each receiver with whatever arguments it can accept. 158 # Return a list of tuple pairs [(receiver, response), ... ]. 159 for receiver in self._live_receivers(_make_id(sender)): 160 try: 161 response = receiver(signal=self, sender=sender, **named) 162 except Exception, err: 163 responses.append((receiver, err)) 164 else: 165 responses.append((receiver, response)) 166 return responses 273 167 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 168 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: 169 170 def _live_receivers(self, senderkey): 171 """Filter sequence of receivers to get resolved, live receivers 172 173 This checks for weak references 174 and resolves them, then returning only live 175 receivers. 176 """ 177 none_senderkey = _make_id(None) 178 179 for (receiverkey, r_senderkey), receiver in self.receivers: 180 if r_senderkey == none_senderkey or r_senderkey == senderkey: 305 181 if isinstance(receiver, WEAKREF_TYPES): 182 # Dereference the weak reference. 306 183 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 184 if receiver is not None: 185 yield receiver 186 else: 187 yield receiver 316 188 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 details 189 def _remove_receiver(self, receiver): 190 """Remove dead receivers from connections.""" 191 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] 321 200 322 sender -- the sender of the signal 323 324 if Any, only receivers registered for Any will receive 325 the message. 201 202 def connect(receiver, signal, sender=None, weak=True): 203 """For backward compatibility only. See Signal.connect() 204 """ 205 return signal.connect(receiver, sender, weak) 326 206 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. 207 def disconnect(receiver, signal, sender=None, weak=True): 208 """For backward compatibility only. See Signal.disconnect() 350 209 """ 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 210 signal.disconnect(receiver, sender, weak) 364 211 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. 212 def send(signal, sender=None, **named): 213 """For backward compatibility only. See Signal.send() 373 214 """ 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 215 return signal.send(sender=sender, **named) 386 216 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 217 def sendExact(signal, sender, **named ): 218 """This function is deprecated, as it now has the same 219 meaning as send. 457 220 """ 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 221 return signal.send(sender=sender, **named) -
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/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/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): -
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 * -
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 36 # force cleanup just in case 37 signal.receivers = [] 46 38 47 39 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) 40 a_signal.connect(receiver_1_arg, sender=self) 41 expected = [(receiver_1_arg,"test")] 42 result = a_signal.send(sender=self, val="test") 53 43 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) 44 a_signal.disconnect(receiver_1_arg, sender=self) 45 self._testIsClean(a_signal) 46 47 def testIgnoredSender(self): 48 a_signal.connect(receiver_1_arg) 49 expected = [(receiver_1_arg,"test")] 50 result = a_signal.send(sender=self, val="test") 64 51 self.assertEqual(result, expected) 65 disconnect(x, signal) 66 self.assertEqual(list(getAllReceivers(None,signal)), []) 67 self._testIsClean() 52 a_signal.disconnect(receiver_1_arg) 53 self._testIsClean(a_signal) 68 54 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 55 def testGarbageCollected(self): 96 56 a = Callable() 97 b = Dummy() 98 signal = 'this' 99 connect(a.a, signal, b) 57 a_signal.connect(a.a, sender=self) 100 58 expected = [] 101 59 del a 102 60 garbage_collect() 103 result = send('this',b, a=b)61 result = a_signal.send(sender=self, val="test") 104 62 self.assertEqual(result, expected) 105 self.assertEqual(list(getAllReceivers(b,signal)), []) 106 self._testIsClean() 63 self._testIsClean(a_signal) 107 64 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 65 def testMultipleRegistration(self): 126 66 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) 67 a_signal.connect(a) 68 a_signal.connect(a) 69 a_signal.connect(a) 70 a_signal.connect(a) 71 a_signal.connect(a) 72 a_signal.connect(a) 73 result = a_signal.send(sender=self, val="test") 136 74 self.assertEqual(len(result), 1) 137 self.assertEqual(len( list(getAllReceivers(b,signal))), 1)75 self.assertEqual(len(a_signal.receivers), 1) 138 76 del a 139 del b140 77 del result 141 78 garbage_collect() 142 self._testIsClean() 79 self._testIsClean(a_signal) 80 81 def testUidRegistration(self): 82 def uid_based_receiver_1(**kwargs): 83 pass 84 85 def uid_based_receiver_2(**kwargs): 86 pass 87 88 a_signal.connect(uid_based_receiver_1, dispatch_uid = "uid") 89 a_signal.connect(uid_based_receiver_2, dispatch_uid = "uid") 90 self.assertEqual(len(a_signal.receivers), 1) 91 a_signal.disconnect(dispatch_uid = "uid") 92 self._testIsClean(a_signal) 143 93 144 94 def testRobust(self): 145 95 """Test the sendRobust function""" 146 def fails( ):96 def fails(val, **kwargs): 147 97 raise ValueError('this') 148 a = object() 149 signal = 'this' 150 connect(fails, Any, a) 151 result = robust.sendRobust('this',a, a=a) 98 a_signal.connect(fails) 99 result = a_signal.send_robust(sender=self, val="test") 152 100 err = result[0][1] 153 101 self.assert_(isinstance(err, ValueError)) 154 102 self.assertEqual(err.args, ('this',)) 103 a_signal.disconnect(fails) 104 self._testIsClean(a_signal) 155 105 156 106 def getSuite(): 157 107 return unittest.makeSuite(DispatcherTests,'test') -
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