Ticket #6814: signals_8156-2.diff

File signals_8156-2.diff, 68.0 KB (added by Jacob, 16 years ago)

Jeremy's latest patch

  • django/test/client.py

     
    1111from django.core.handlers.base import BaseHandler
    1212from django.core.handlers.wsgi import WSGIRequest
    1313from django.core.signals import got_request_exception
    14 from django.dispatch import dispatcher
    1514from django.http import SimpleCookie, HttpRequest
    1615from django.template import TemplateDoesNotExist
    1716from django.test import signals
     
    5958        if self._request_middleware is None:
    6059            self.load_middleware()
    6160
    62         dispatcher.send(signal=signals.request_started)
     61        signals.request_started.send(sender=self.__class__)
    6362        try:
    6463            request = WSGIRequest(environ)
    6564            response = self.get_response(request)
     
    6968                response = middleware_method(request, response)
    7069            response = self.apply_response_fixes(request, response)
    7170        finally:
    72             dispatcher.send(signal=signals.request_finished)
     71            signals.request_finished.send(sender=self.__class__)
    7372
    7473        return response
    7574
    76 def store_rendered_templates(store, signal, sender, template, context):
     75def store_rendered_templates(store, signal, sender, template, context, **kwargs):
    7776    """
    7877    Stores templates and contexts that are rendered.
    7978    """
     
    160159        self.cookies = SimpleCookie()
    161160        self.exc_info = None
    162161
    163     def store_exc_info(self, *args, **kwargs):
     162    def store_exc_info(self, **kwargs):
    164163        """
    165164        Stores exceptions when they are generated by a view.
    166165        """
     
    202201        # callback function.
    203202        data = {}
    204203        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)
    206205
    207206        # 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)
    209208
    210209        try:
    211210            response = self.handler(environ)
  • django/test/signals.py

     
    1 template_rendered = object()
    2  No newline at end of file
     1from django.dispatch.dispatcher import Signal
     2
     3template_rendered = Signal(providing_args=["template", "context"])
  • django/test/utils.py

     
    33from django.db import connection, get_creation_module
    44from django.core import mail
    55from django.core.management import call_command
    6 from django.dispatch import dispatcher
    76from django.test import signals
    87from django.template import Template
    98from django.utils.translation import deactivate
     
    1716    An instrumented Template render method, providing a signal
    1817    that can be intercepted by the test system Client
    1918    """
    20     dispatcher.send(signal=signals.template_rendered, sender=self, template=self, context=context)
     19    signals.template_rendered.send(sender=self, template=self, context=context)
    2120    return self.nodelist.render(context)
    2221
    2322class TestSMTPConnection(object):
  • django/db/models/sql/query.py

     
    1111
    1212from django.utils.tree import Node
    1313from django.utils.datastructures import SortedDict
    14 from django.dispatch import dispatcher
    1514from django.db import connection
    1615from django.db.models import signals
    1716from django.db.models.fields import FieldDoesNotExist
     
    16701669            sentinel):
    16711670        yield [r[:-trim] for r in rows]
    16721671
    1673 def setup_join_cache(sender):
     1672def setup_join_cache(sender, **kwargs):
    16741673    """
    16751674    The information needed to join between model fields is something that is
    16761675    invariant over the life of the model, so we cache it in the model's Options
     
    16801679    """
    16811680    sender._meta._join_cache = {}
    16821681
    1683 dispatcher.connect(setup_join_cache, signal=signals.class_prepared)
     1682signals.class_prepared.connect(setup_join_cache)
    16841683
  • django/db/models/base.py

     
    1919from django.db import connection, transaction
    2020from django.db.models import signals
    2121from django.db.models.loading import register_models, get_model
    22 from django.dispatch import dispatcher
    2322from django.utils.functional import curry
    2423from django.utils.encoding import smart_str, force_unicode, smart_unicode
    2524from django.core.files.move import file_move_safe
     
    161160        if hasattr(cls, 'get_absolute_url'):
    162161            cls.get_absolute_url = curry(get_absolute_url, opts, cls.get_absolute_url)
    163162
    164         dispatcher.send(signal=signals.class_prepared, sender=cls)
     163        signals.class_prepared.send(sender=cls)
    165164
    166165
    167166class Model(object):
    168167    __metaclass__ = ModelBase
    169168
    170169    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)
    172171
    173172        # There is a rather weird disparity here; if kwargs, it's set, then args
    174173        # overrides it. It should be one or the other; don't duplicate the work
     
    237236                    pass
    238237            if kwargs:
    239238                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)
    241240
    242241    def __repr__(self):
    243242        return smart_str(u'<%s: %s>' % (self.__class__.__name__, unicode(self)))
     
    286285            cls = self.__class__
    287286            meta = self._meta
    288287            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)
    291289        else:
    292290            meta = cls._meta
    293291            signal = False
     
    349347        transaction.commit_unless_managed()
    350348
    351349        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)
    354352
    355353    save_base.alters_data = True
    356354
  • django/db/models/manager.py

     
    11import copy
    22
    33from django.db.models.query import QuerySet, EmptyQuerySet, insert_query
    4 from django.dispatch import dispatcher
    54from django.db.models import signals
    65from django.db.models.fields import FieldDoesNotExist
    76
    8 def ensure_default_manager(sender):
     7def ensure_default_manager(sender, **kwargs):
    98    cls = sender
    109    if not getattr(cls, '_default_manager', None) and not cls._meta.abstract:
    1110        # Create the default manager, if needed.
     
    1615            pass
    1716        cls.add_to_class('objects', Manager())
    1817
    19 dispatcher.connect(ensure_default_manager, signal=signals.class_prepared)
     18signals.class_prepared.connect(ensure_default_manager)
    2019
    2120class Manager(object):
    2221    # Tracks each time a Manager instance is created. Used to retain order.
  • django/db/models/manipulators.py

     
    22from django import oldforms
    33from django.core import validators
    44from django.db.models.fields import FileField, AutoField
    5 from django.dispatch import dispatcher
    65from django.db.models import signals
    76from django.utils.functional import curry
    87from django.utils.datastructures import DotExpandedDict
     
    1110from django.utils.translation import ugettext as _
    1211from django.utils import datetime_safe
    1312
    14 def add_manipulators(sender):
     13def add_manipulators(sender, **kwargs):
    1514    cls = sender
    1615    cls.add_to_class('AddManipulator', AutomaticAddManipulator)
    1716    cls.add_to_class('ChangeManipulator', AutomaticChangeManipulator)
    1817
    19 dispatcher.connect(add_manipulators, signal=signals.class_prepared)
     18signals.class_prepared.connect(add_manipulators)
    2019
    2120class ManipulatorDescriptor(object):
    2221    # This class provides the functionality that makes the default model
  • django/db/models/fields/__init__.py

     
    1010from django.db import connection, get_creation_module
    1111from django.db.models import signals
    1212from django.db.models.query_utils import QueryWrapper
    13 from django.dispatch import dispatcher
    1413from django.conf import settings
    1514from django.core import validators
    1615from django import oldforms
     
    824823        setattr(cls, 'get_%s_url' % self.name, curry(cls._get_FIELD_url, field=self))
    825824        setattr(cls, 'get_%s_size' % self.name, curry(cls._get_FIELD_size, field=self))
    826825        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)
    828827
    829     def delete_file(self, instance):
     828    def delete_file(self, instance, **kwargs):
    830829        if getattr(instance, self.attname):
    831830            file_name = getattr(instance, 'get_%s_filename' % self.name)()
    832831            # If the file exists and no other object of this type references it,
  • django/db/models/fields/related.py

     
    99from django.core import validators
    1010from django import oldforms
    1111from django import forms
    12 from django.dispatch import dispatcher
    1312
    1413try:
    1514    set
     
    7473        value = (cls, field, operation)
    7574        pending_lookups.setdefault(key, []).append(value)
    7675
    77 def do_pending_lookups(sender):
     76def do_pending_lookups(sender, **kwargs):
    7877    """
    7978    Handle any pending relations to the sending model. Sent from class_prepared.
    8079    """
     
    8281    for cls, field, operation in pending_lookups.pop(key, []):
    8382        operation(field, sender, cls)
    8483
    85 dispatcher.connect(do_pending_lookups, signal=signals.class_prepared)
     84signals.class_prepared.connect(do_pending_lookups)
    8685
    8786def manipulator_valid_rel_key(f, self, field_data, all_data):
    8887    "Validates that the value is a valid foreign key"
  • django/db/models/signals.py

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

     
    88from django.db.models.fields import DateField
    99from django.db.models.query_utils import Q, select_related_descend
    1010from django.db.models import signals, sql
    11 from django.dispatch import dispatcher
    1211from django.utils.datastructures import SortedDict
    1312
    1413
     
    827826
    828827        # Pre-notify all instances to be deleted.
    829828        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)
    832830
    833831        pk_list = [pk for pk,instance in items]
    834832        del_query = sql.DeleteQuery(cls, connection)
     
    862860                if field.rel and field.null and field.rel.to in seen_objs:
    863861                    setattr(instance, field.attname, None)
    864862
    865             dispatcher.send(signal=signals.post_delete, sender=cls,
    866                     instance=instance)
     863            signals.post_delete.send(sender=cls, instance=instance)
    867864            setattr(instance, cls._meta.pk.attname, None)
    868865
    869866    transaction.commit_unless_managed()
  • django/db/__init__.py

     
    22from django.conf import settings
    33from django.core import signals
    44from django.core.exceptions import ImproperlyConfigured
    5 from django.dispatch import dispatcher
    65from django.utils.functional import curry
    76
    87__all__ = ('backend', 'connection', 'DatabaseError', 'IntegrityError')
     
    5857
    5958# Register an event that closes the database connection
    6059# when a Django request is finished.
    61 dispatcher.connect(connection.close, signal=signals.request_finished)
     60def close_connection(**kwargs):
     61    connection.close()
     62signals.request_finished.connect(close_connection)
    6263
    6364# Register an event that resets connection.queries
    6465# when a Django request is started.
    65 def reset_queries():
     66def reset_queries(**kwargs):
    6667    connection.queries = []
    67 dispatcher.connect(reset_queries, signal=signals.request_started)
     68signals.request_started.connect(reset_queries)
    6869
    6970# Register an event that rolls back the connection
    7071# when a Django request has an exception.
    71 def _rollback_on_exception():
     72def _rollback_on_exception(**kwargs):
    7273    from django.db import transaction
    7374    transaction.rollback_unless_managed()
    74 dispatcher.connect(_rollback_on_exception, signal=signals.got_request_exception)
     75signals.got_request_exception.connect(_rollback_on_exception)
  • django/core/signals.py

     
    1 request_started = object()
    2 request_finished = object()
    3 got_request_exception = object()
     1from django.dispatch.dispatcher import Signal
     2
     3request_started = Signal()
     4request_finished = Signal()
     5got_request_exception = Signal(providing_args=["request"])
  • django/core/handlers/wsgi.py

     
    99from django.core import signals
    1010from django.core.handlers import base
    1111from django.core.urlresolvers import set_script_prefix
    12 from django.dispatch import dispatcher
    1312from django.utils import datastructures
    1413from django.utils.encoding import force_unicode
    1514
     
    207206            self.initLock.release()
    208207
    209208        set_script_prefix(base.get_script_name(environ))
    210         dispatcher.send(signal=signals.request_started)
     209        signals.request_started.send(sender=self.__class__)
    211210        try:
    212211            try:
    213212                request = self.request_class(environ)
     
    221220                    response = middleware_method(request, response)
    222221                response = self.apply_response_fixes(request, response)
    223222        finally:
    224             dispatcher.send(signal=signals.request_finished)
     223            signals.request_finished.send(sender=self.__class__)
    225224
    226225        try:
    227226            status_text = STATUS_CODE_TEXT[response.status_code]
  • django/core/handlers/base.py

     
    22
    33from django import http
    44from django.core import signals
    5 from django.dispatch import dispatcher
    65from django.utils.encoding import force_unicode
    76
    87class BaseHandler(object):
     
    122121        except: # Handle everything else, including SuspiciousOperation, etc.
    123122            # Get the exception info now, in case another exception is thrown later.
    124123            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)
    126125            return self.handle_uncaught_exception(request, resolver, exc_info)
    127126
    128127    def handle_uncaught_exception(self, request, resolver, exc_info):
  • django/core/handlers/modpython.py

     
    55from django.core import signals
    66from django.core.handlers.base import BaseHandler
    77from django.core.urlresolvers import set_script_prefix
    8 from django.dispatch import dispatcher
    98from django.utils import datastructures
    109from django.utils.encoding import force_unicode, smart_str
    1110
     
    174173            self.load_middleware()
    175174
    176175        set_script_prefix(req.get_options().get('django.root', ''))
    177         dispatcher.send(signal=signals.request_started)
     176        signals.request_started.send(sender=self.__class__)
    178177        try:
    179178            try:
    180179                request = self.request_class(req)
     
    188187                    response = middleware_method(request, response)
    189188                response = self.apply_response_fixes(request, response)
    190189        finally:
    191             dispatcher.send(signal=signals.request_finished)
     190            signals.request_finished.send(sender=self.__class__)
    192191
    193192        # Convert our custom HttpResponse object back into the mod_python req.
    194193        req.content_type = response['Content-Type']
  • django/core/management/commands/flush.py

     
    1515    def handle_noargs(self, **options):
    1616        from django.conf import settings
    1717        from django.db import connection, transaction, models
    18         from django.dispatch import dispatcher
    1918        from django.core.management.sql import sql_flush, emit_post_sync_signal
    2019
    2120        verbosity = int(options.get('verbosity', 1))
  • django/core/management/sql.py

     
    492492        app_name = app.__name__.split('.')[-2]
    493493        if verbosity >= 2:
    494494            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 mechanism
    2 """
    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, getAllReceivers
    3 from django.dispatch.robustapply import robustApply
    4 
    5 def sendRobust(
    6     signal=Any,
    7     sender=Anonymous,
    8     *arguments, **named
    9 ):
    10     """Send signal from sender to all connected receivers catching errors
    11    
    12     signal -- (hashable) signal value, see connect for details
    13 
    14     sender -- the sender of the signal
    15    
    16         if Any, only receivers registered for Any will receive
    17         the message.
    18 
    19         if Anonymous, only receivers registered to receive
    20         messages from Anonymous or Any will receive the message
    21 
    22         Otherwise can be any python object (normally one
    23         registered with a connect if you actually want
    24         something to occur).
    25 
    26     arguments -- positional arguments which will be passed to
    27         *all* receivers. Note that this may raise TypeErrors
    28         if the receivers do not allow the particular arguments.
    29         Note also that arguments are applied before named
    30         arguments, so they should be used with care.
    31 
    32     named -- named arguments which will be filtered according
    33         to the parameters of the receivers to only provide those
    34         acceptable to the receiver.
    35 
    36     Return a list of tuple pairs [(receiver, response), ... ]
    37 
    38     if any receiver raises an error (specifically any subclass of Exception),
    39     the error instance is returned as the result for that receiver.
    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                 **named
    52             )
    53         except Exception, err:
    54             responses.append((receiver, err))
    55         else:
    56             responses.append((receiver, response))
    57     return responses
  • django/dispatch/__init__.py

     
    11"""Multi-consumer multi-producer dispatching mechanism
     2
     3Originally based on pydispatch (BSD) http://pypi.python.org/pypi/PyDispatcher/2.0.1
     4See license.txt for original license.
     5
     6Heavily modified for Django's purposes.
    27"""
    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 mechanism
    2 
    3 Provides a function "call", which can sort out
    4 what arguments a given callable object can take,
    5 and subset the given arguments to match only
    6 those which are acceptable.
    7 """
    8 
    9 def function( receiver ):
    10     """Get function-like callable object for given receiver
    11 
    12     returns (function_or_method, codeObject, fromMethod)
    13 
    14     If fromMethod is true, then the callable already
    15     has its first argument bound
    16     """
    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, 1
    25     elif not hasattr( receiver, 'func_code'):
    26         raise ValueError('unknown reciever type %s %s'%(receiver, type(receiver)))
    27     return receiver, receiver.func_code, 0
    28 
    29 def robustApply(receiver, *arguments, **named):
    30     """Call receiver with arguments and an appropriate subset of named
    31     """
    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, therefore
    43         # 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-dispatching
    2 
    3 dispatcher is the core of the PyDispatcher system,
    4 providing the primary API and the core logic for the
    5 system.
    6 
    7 Module attributes of note:
    8 
    9     Any -- Singleton used to signal either "Any Sender" or
    10         "Any Signal".  See documentation of the _Any class.
    11     Anonymous -- Singleton used to signal "Anonymous Sender"
    12         See documentation of the _Anonymous class.
    13 
    14 Internal attributes:
    15     WEAKREF_TYPES -- tuple of types/classes which represent
    16         weak references to receivers, and thus must be de-
    17         referenced on retrieval to retrieve the callable
    18         object
    19     connections -- { senderkey (id) : { signal : [receivers...]}}
    20     senders -- { senderkey (id) : weakref(sender) }
    21         used for cleaning up sender references on sender
    22         deletion
    23     sendersBack -- { receiverkey (id) : [senderkey (id)...] }
    24         used for cleaning up receiver references on receiver
    25         deletion, (considerably speeds up the cleanup process
    26         vs. the original code.)
    27 """
    281import weakref
    29 from django.dispatch import saferef, robustapply, errors
     2try:
     3    set
     4except NameError:
     5    from sets import Set as set # Python 2.3 fallback
    306
    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]
     7from django.dispatch import saferef
    348
    35 
    36 class _Parameter:
    37     """Used to represent default parameter values."""
    38     def __repr__(self):
    39         return self.__class__.__name__
    40 
    41 class _Any(_Parameter):
    42     """Singleton used to signal either "Any Sender" or "Any Signal"
    43 
    44     The Any object can be used with connect, disconnect,
    45     send, or sendExact to signal that the parameter given
    46     Any should react to all senders/signals, not just
    47     a particular sender/signal.
    48     """
    49 Any = _Any()
    50 
    51 class _Anonymous(_Parameter):
    52     """Singleton used to signal "Anonymous Sender"
    53 
    54     The Anonymous object is used to signal that the sender
    55     of a message is not specified (as distinct from being
    56     "any sender").  Registering callbacks for Anonymous
    57     will only receive messages sent without senders.  Sending
    58     with anonymous will only send messages to those receivers
    59     registered for Any or Anonymous.
    60 
    61     Note:
    62         The default sender for connect is Any, while the
    63         default sender for send is Anonymous.  This has
    64         the effect that if you do not specify any senders
    65         in either function then all messages are routed
    66         as though there was a single sender (Anonymous)
    67         being used everywhere.
    68     """
    69 Anonymous = _Anonymous()
    70 
    719WEAKREF_TYPES = (weakref.ReferenceType, saferef.BoundMethodWeakref)
    7210
    73 connections = {}
    74 senders = {}
    75 sendersBack = {}
     11def _make_id(target):
     12    if hasattr(target, 'im_func'):
     13        return (id(target.im_self), id(target.im_func))
     14    return id(target)
    7615
    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).
     16class Signal(object):
     17    """Base class for all signals
    8818   
    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    """
    10422   
    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).
    10841       
    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.
    11356   
    114         if Any, receiver will receive the indicated signals
    115         from any sender.
     57        returns None
     58        """
     59        from django.conf import settings
    11660       
    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)."
    12265       
    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
    12769
    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))
    13771
    138     signals = connections.setdefault(senderkey, {})
     72        if weak:
     73            receiver = saferef.safeRef(receiver, onDelete=self._remove_receiver)
    13974
    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)
    16982
    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))
    17198
     99        uid = getattr(receiver, 'dispatch_uid', None)
    172100
     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.
    173114
    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), ... ].
    196116       
    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        """
    228122
    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
    231126
    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
    235131
    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
    242134
    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).
    251138
    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.
    254143
    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
    268146
     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        """
    269150
     151        responses = []
     152        if not self.receivers:
     153            return responses
    270154
    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
    273165
    274     This gets all dereferenced receivers which should receive
    275     the given signal from sender, each receiver should
    276     be produced only once by the resulting generator
    277     """
    278     receivers = {}
    279     # Get receivers that receive *this* signal from *this* sender.
    280     # Add receivers that receive *any* signal from *this* sender.
    281     # Add receivers that receive *this* signal from *any* sender.
    282     # Add receivers that receive *any* signal from *any* sender.
    283     l = []
    284     i = id(sender)
    285     if i in connections:
    286         sender_receivers = connections[i]
    287         if signal in sender_receivers:
    288             l.extend(sender_receivers[signal])
    289         if signal is not Any and Any in sender_receivers:
    290             l.extend(sender_receivers[Any])
    291166
    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:
    305179                if isinstance(receiver, WEAKREF_TYPES):
     180                    # Dereference the weak reference.
    306181                    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
    316186
    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
     187    def _remove_receiver(self, receiver):
     188        """Remove dead receivers from connections."""
     189       
     190        uid = getattr(receiver, 'dispatch_uid', None)
    321191
    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)
    326202
    327         if Anonymous, only receivers registered to receive
    328         messages from Anonymous or Any will receive the message
     203           
     204def connect(receiver, signal, sender=None, weak=True):
     205    """For backward compatibility only. See Signal.connect()
     206    """
     207    return signal.connect(receiver, sender, weak)
    329208
    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.
     209def disconnect(receiver, signal, sender=None, weak=True):
     210    """For backward compatibility only. See Signal.disconnect()
    350211    """
    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)
    364213
    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.
     214def send(signal, sender=None, **named):
     215    """For backward compatibility only. See Signal.send()
    373216    """
    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)
    386218
    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
     219def sendExact(signal, sender, **named ):
     220    """This function is deprecated, as it now has the same
     221    meaning as send.
    457222    """
    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

     
    22Creates the default Site object.
    33"""
    44
    5 from django.dispatch import dispatcher
    65from django.db.models import signals
    76from django.contrib.sites.models import Site
    87from django.contrib.sites import models as site_app
    98
    10 def create_default_site(app, created_models, verbosity):
     9def create_default_site(app, created_models, verbosity, **kwargs):
    1110    if Site in created_models:
    1211        if verbosity >= 2:
    1312            print "Creating example.com Site object"
     
    1514        s.save()
    1615    Site.objects.clear_cache()
    1716
    18 dispatcher.connect(create_default_site, sender=site_app, signal=signals.post_syncdb)
     17signals.post_syncdb.connect(create_default_site, sender=site_app)
  • django/contrib/contenttypes/management.py

     
    11from django.contrib.contenttypes.models import ContentType
    2 from django.dispatch import dispatcher
    32from django.db.models import get_apps, get_models, signals
    43from django.utils.encoding import smart_unicode
    54
    6 def update_contenttypes(app, created_models, verbosity=2):
     5def update_contenttypes(app, created_models, verbosity=2, **kwargs):
    76    """
    87    Creates content types for models in the given app, removing any model
    98    entries that no longer have a matching model class.
     
    3736    for app in get_apps():
    3837        update_contenttypes(app, None, verbosity)
    3938
    40 dispatcher.connect(update_contenttypes, signal=signals.post_syncdb)
     39signals.post_syncdb.connect(update_contenttypes)
    4140
    4241if __name__ == "__main__":
    4342    update_all_contenttypes()
  • django/contrib/contenttypes/generic.py

     
    88from django.db.models import signals
    99from django.db.models.fields.related import RelatedField, Field, ManyToManyRel
    1010from django.db.models.loading import get_model
    11 from django.dispatch import dispatcher
    1211from django.utils.functional import curry
    1312
    1413class GenericForeignKey(object):
     
    2928        self.cache_attr = "_%s_cache" % name
    3029
    3130        # 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)
    3332
    3433        # Connect myself as the descriptor for this field
    3534        setattr(cls, name, self)
    3635
    37     def instance_pre_init(self, signal, sender, args, kwargs):
     36    def instance_pre_init(self, signal, sender, args, kwargs, **_kwargs):
    3837        """
    3938        Handles initializing an object with the generic FK instaed of
    4039        content-type/object-id fields.
  • django/contrib/auth/management/__init__.py

     
    22Creates permissions for all installed apps that need permissions.
    33"""
    44
    5 from django.dispatch import dispatcher
    65from django.db.models import get_models, signals
    76from django.contrib.auth import models as auth_app
    87
     
    1615        perms.append((_get_permission_codename(action, opts), u'Can %s %s' % (action, opts.verbose_name_raw)))
    1716    return perms + list(opts.permissions)
    1817
    19 def create_permissions(app, created_models, verbosity):
     18def create_permissions(app, created_models, verbosity, **kwargs):
    2019    from django.contrib.contenttypes.models import ContentType
    2120    from django.contrib.auth.models import Permission
    2221    app_models = get_models(app)
     
    2928                defaults={'name': name, 'content_type': ctype})
    3029            if created and verbosity >= 2:
    3130                print "Adding permission '%s'" % p
     31create_permissions.dispatch_uid = "django.contrib.auth.management.create_permissions"
    3232
    3333def create_superuser(app, created_models, verbosity, **kwargs):
    3434    from django.contrib.auth.models import User
     
    4444            if confirm == 'yes':
    4545                call_command("createsuperuser", interactive=True)
    4646            break
     47create_superuser.dispatch_uid = "django.contrib.auth.management.create_superuser"
    4748
    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
     49signals.post_syncdb.connect(create_permissions)
     50signals.post_syncdb.connect(create_superuser, sender=auth_app)
     51 No newline at end of file
  • tests/modeltests/signals/models.py

     
    33"""
    44
    55from django.db import models
    6 from django.dispatch import dispatcher
    76
    87class Person(models.Model):
    98    first_name = models.CharField(max_length=20)
     
    1211    def __unicode__(self):
    1312        return u"%s %s" % (self.first_name, self.last_name)
    1413
    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):
     14def pre_save_test(signal, sender, instance, **kwargs):
    2315    print 'pre_save signal,', instance
    2416    if kwargs.get('raw'):
    2517        print 'Is raw'
    2618
    27 def post_save_test(sender, instance, **kwargs):
     19def post_save_test(signal, sender, instance, **kwargs):
    2820    print 'post_save signal,', instance
    2921    if 'created' in kwargs:
    3022        if kwargs['created']:
     
    3426    if kwargs.get('raw'):
    3527        print 'Is raw'
    3628
    37 def pre_delete_test(sender, instance, **kwargs):
     29def pre_delete_test(signal, sender, instance, **kwargs):
    3830    print 'pre_delete signal,', instance
    3931    print 'instance.id is not None: %s' % (instance.id != None)
    4032
    41 def post_delete_test(sender, instance, **kwargs):
     33def post_delete_test(signal, sender, instance, **kwargs):
    4234    print 'post_delete signal,', instance
    4335    print 'instance.id is None: %s' % (instance.id == None)
    4436
    4537__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)
    5242
    5343>>> p1 = Person(first_name='John', last_name='Smith')
    5444>>> p1.save()
    55 pre_save_nokwargs signal
    5645pre_save signal, John Smith
    57 post_save_nokwargs signal
    5846post_save signal, John Smith
    5947Is created
    6048
    6149>>> p1.first_name = 'Tom'
    6250>>> p1.save()
    63 pre_save_nokwargs signal
    6451pre_save signal, Tom Smith
    65 post_save_nokwargs signal
    6652post_save signal, Tom Smith
    6753Is updated
    6854
    6955# Calling an internal method purely so that we can trigger a "raw" save.
    7056>>> p1.save_base(raw=True)
    71 pre_save_nokwargs signal
    7257pre_save signal, Tom Smith
    7358Is raw
    74 post_save_nokwargs signal
    7559post_save signal, Tom Smith
    7660Is updated
    7761Is raw
     
    8569>>> p2 = Person(first_name='James', last_name='Jones')
    8670>>> p2.id = 99999
    8771>>> p2.save()
    88 pre_save_nokwargs signal
    8972pre_save signal, James Jones
    90 post_save_nokwargs signal
    9173post_save signal, James Jones
    9274Is created
    9375
    9476>>> p2.id = 99998
    9577>>> p2.save()
    96 pre_save_nokwargs signal
    9778pre_save signal, James Jones
    98 post_save_nokwargs signal
    9979post_save signal, James Jones
    10080Is created
    10181
     
    10888>>> Person.objects.all()
    10989[<Person: James Jones>]
    11090
    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)
    11795"""}
  • tests/regressiontests/dispatch/tests/__init__.py

     
    22Unit-tests for the dispatch project
    33"""
    44
    5 from test_dispatcher import *
    6 from test_robustapply import *
    75from test_saferef import *
     6from 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 unittest
    4 
    5 def noArgument():
    6     pass
    7 
    8 def oneArgument(blah):
    9     pass
    10 
    11 def twoArgument(blah, other):
    12     pass
    13 
    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
     1from django.dispatch.dispatcher import Signal
    32import unittest
    43import copy
    54import sys
     
    1514    def garbage_collect():
    1615        gc.collect()
    1716
    18 def x(a):
    19     return a
     17def receiver_1_arg(val, **kwargs):
     18    return val
    2019
    21 class Dummy(object):
    22     pass
    23 
    2420class Callable(object):
    25     def __call__(self, a):
    26         return a
     21    def __call__(self, val, **kwargs):
     22        return val
    2723   
    28     def a(self, a):
    29         return a
     24    def a(self, val, **kwargs):
     25        return val
    3026
     27a_signal = Signal(providing_args=["val"])
     28
    3129class DispatcherTests(unittest.TestCase):
    3230    """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):
    4233        """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()
    4640   
    4741    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")
    5345        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")
    6453        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)
    6856   
    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    
    9557    def testGarbageCollected(self):
    9658        a = Callable()
    97         b = Dummy()
    98         signal = 'this'
    99         connect(a.a, signal, b)
     59        a_signal.connect(a.a, sender=self)
    10060        expected = []
    10161        del a
    10262        garbage_collect()
    103         result = send('this',b, a=b)
     63        result = a_signal.send(sender=self, val="test")
    10464        self.assertEqual(result, expected)
    105         self.assertEqual(list(getAllReceivers(b,signal)), [])
    106         self._testIsClean()
     65        self._testIsClean(a_signal)
    10766   
    108     def testGarbageCollectedObj(self):
    109         class x:
    110             def __call__(self, a):
    111                 return a
    112         a = Callable()
    113         b = Dummy()
    114         signal = 'this'
    115         connect(a, signal, b)
    116         expected = []
    117         del a
    118         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    
    12567    def testMultipleRegistration(self):
    12668        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")
    13676        self.assertEqual(len(result), 1)
    137         self.assertEqual(len(list(getAllReceivers(b,signal))), 1)
     77        self.assertEqual(len(a_signal.receivers), 1)
    13878        del a
    139         del b
    14079        del result
    14180        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)
    14397   
    14498    def testRobust(self):
    14599        """Test the sendRobust function"""
    146         def fails():
     100        def fails(val, **kwargs):
    147101            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")
    152104        err = result[0][1]
    153105        self.assert_(isinstance(err, ValueError))
    154106        self.assertEqual(err.args, ('this',))
     107        a_signal.disconnect(fails)
     108        self._testIsClean(a_signal)
    155109
    156110def getSuite():
    157111    return unittest.makeSuite(DispatcherTests,'test')
Back to Top