Skip to content

Commit

Permalink
Fixed django#8285: signal handlers that aren't functions work under D…
Browse files Browse the repository at this point in the history
…EBUG. This slightly loosens the sanity check, but things that are valid under production shouldn't fail under debug.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@8546 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
jacobian committed Aug 25, 2008
1 parent 1aa4889 commit 0a6314f
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 5 deletions.
20 changes: 18 additions & 2 deletions django/dispatch/dispatcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,26 @@ def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
"""
from django.conf import settings

# If DEBUG is on, check that we got a good receiver
if settings.DEBUG:
import inspect
assert inspect.getargspec(receiver)[2] is not None, \
"Signal receivers must accept keyword arguments (**kwargs)."
assert callable(receiver), "Signal receivers must be callable."

# Check for **kwargs
# Not all callables are inspectable with getargspec, so we'll
# try a couple different ways but in the end fall back on assuming
# it is -- we don't want to prevent registration of valid but weird
# callables.
try:
argspec = inspect.getargspec(receiver)
except TypeError:
try:
argspec = inspect.getargspec(receiver.__call__)
except (TypeError, AttributeError):
argspec = None
if argspec:
assert argspec[2] is not None, \
"Signal receivers must accept keyword arguments (**kwargs)."

if dispatch_uid:
lookup_key = (dispatch_uid, _make_id(sender))
Expand Down
10 changes: 7 additions & 3 deletions tests/modeltests/signals/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,13 @@ def pre_delete_test(signal, sender, instance, **kwargs):
print 'pre_delete signal,', instance
print 'instance.id is not None: %s' % (instance.id != None)

def post_delete_test(signal, sender, instance, **kwargs):
print 'post_delete signal,', instance
print 'instance.id is None: %s' % (instance.id == None)
# #8285: signals can be any callable
class PostDeleteHandler(object):
def __call__(self, signal, sender, instance, **kwargs):
print 'post_delete signal,', instance
print 'instance.id is None: %s' % (instance.id == None)

post_delete_test = PostDeleteHandler()

__test__ = {'API_TESTS':"""
>>> models.signals.pre_save.connect(pre_save_test)
Expand Down

0 comments on commit 0a6314f

Please sign in to comment.