Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #8285: signal handlers that aren't functions work under DEBUG. …

…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...
commit 0a6314f249f02d928bf5cf29def470e180898e0d 1 parent 1aa4889
Jacob Kaplan-Moss authored August 25, 2008
20  django/dispatch/dispatcher.py
@@ -63,10 +63,26 @@ def connect(self, receiver, sender=None, weak=True, dispatch_uid=None):
63 63
         """
64 64
         from django.conf import settings
65 65
         
  66
+        # If DEBUG is on, check that we got a good receiver
66 67
         if settings.DEBUG:
67 68
             import inspect
68  
-            assert inspect.getargspec(receiver)[2] is not None, \
69  
-                "Signal receivers must accept keyword arguments (**kwargs)."
  69
+            assert callable(receiver), "Signal receivers must be callable."
  70
+            
  71
+            # Check for **kwargs
  72
+            # Not all callables are inspectable with getargspec, so we'll
  73
+            # try a couple different ways but in the end fall back on assuming
  74
+            # it is -- we don't want to prevent registration of valid but weird
  75
+            # callables.
  76
+            try:
  77
+                argspec = inspect.getargspec(receiver)
  78
+            except TypeError:
  79
+                try:
  80
+                    argspec = inspect.getargspec(receiver.__call__)
  81
+                except (TypeError, AttributeError):
  82
+                    argspec = None
  83
+            if argspec:
  84
+                assert argspec[2] is not None, \
  85
+                    "Signal receivers must accept keyword arguments (**kwargs)."
70 86
         
71 87
         if dispatch_uid:
72 88
             lookup_key = (dispatch_uid, _make_id(sender))
10  tests/modeltests/signals/models.py
@@ -30,9 +30,13 @@ def pre_delete_test(signal, sender, instance, **kwargs):
30 30
     print 'pre_delete signal,', instance
31 31
     print 'instance.id is not None: %s' % (instance.id != None)
32 32
 
33  
-def post_delete_test(signal, sender, instance, **kwargs):
34  
-    print 'post_delete signal,', instance
35  
-    print 'instance.id is None: %s' % (instance.id == None)
  33
+# #8285: signals can be any callable
  34
+class PostDeleteHandler(object):
  35
+    def __call__(self, signal, sender, instance, **kwargs):
  36
+        print 'post_delete signal,', instance
  37
+        print 'instance.id is None: %s' % (instance.id == None)
  38
+
  39
+post_delete_test = PostDeleteHandler()
36 40
 
37 41
 __test__ = {'API_TESTS':"""
38 42
 >>> models.signals.pre_save.connect(pre_save_test)

0 notes on commit 0a6314f

Please sign in to comment.
Something went wrong with that request. Please try again.