Browse Source

Fixed #16245 -- Included traceback in send_robust()'s response

Exceptions from the (receiver, exception) tuples returned by
``send_robust()`` now have always their traceback attached as their
``__traceback__`` argument.
Unai Zalakain 11 years ago
parent
commit
ebb0279f4a

+ 4 - 1
django/dispatch/dispatcher.py

@@ -220,7 +220,8 @@ class Signal(object):
 
 
         If any receiver raises an error (specifically any subclass of
         If any receiver raises an error (specifically any subclass of
         Exception), the error instance is returned as the result for that
         Exception), the error instance is returned as the result for that
-        receiver.
+        receiver. The traceback is always attached to the error at
+        ``__traceback__``.
         """
         """
         responses = []
         responses = []
         if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
         if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS:
@@ -232,6 +233,8 @@ class Signal(object):
             try:
             try:
                 response = receiver(signal=self, sender=sender, **named)
                 response = receiver(signal=self, sender=sender, **named)
             except Exception as err:
             except Exception as err:
+                if not hasattr(err, '__traceback__'):
+                    err.__traceback__ = sys.exc_info()[2]
                 responses.append((receiver, err))
                 responses.append((receiver, err))
             else:
             else:
                 responses.append((receiver, response))
                 responses.append((receiver, response))

+ 3 - 1
docs/releases/1.8.txt

@@ -153,7 +153,9 @@ Models
 Signals
 Signals
 ^^^^^^^
 ^^^^^^^
 
 
-* ...
+* Exceptions from the ``(receiver, exception)`` tuples returned by
+  :meth:`Signal.send_robust() <django.dispatch.Signal.send_robust>` now have
+  their traceback attached as a ``__traceback__`` attribute.
 
 
 Templates
 Templates
 ^^^^^^^^^
 ^^^^^^^^^

+ 5 - 0
docs/topics/signals.txt

@@ -274,6 +274,11 @@ be notified of a signal in the face of an error.
 and ensures all receivers are notified of the signal. If an error occurs, the
 and ensures all receivers are notified of the signal. If an error occurs, the
 error instance is returned in the tuple pair for the receiver that raised the error.
 error instance is returned in the tuple pair for the receiver that raised the error.
 
 
+.. versionadded:: 1.8
+
+    The tracebacks are present on the ``__traceback__`` attribute
+    of the errors returned when calling ``send_robust()``.
+
 Disconnecting signals
 Disconnecting signals
 =====================
 =====================
 
 

+ 3 - 0
tests/dispatch/tests/test_dispatcher.py

@@ -3,6 +3,7 @@ import sys
 import time
 import time
 import unittest
 import unittest
 import weakref
 import weakref
+from types import TracebackType
 
 
 from django.dispatch import Signal, receiver
 from django.dispatch import Signal, receiver
 
 
@@ -134,6 +135,8 @@ class DispatcherTests(unittest.TestCase):
         err = result[0][1]
         err = result[0][1]
         self.assertIsInstance(err, ValueError)
         self.assertIsInstance(err, ValueError)
         self.assertEqual(err.args, ('this',))
         self.assertEqual(err.args, ('this',))
+        self.assertTrue(hasattr(err, '__traceback__'))
+        self.assertTrue(isinstance(err.__traceback__, TracebackType))
         a_signal.disconnect(fails)
         a_signal.disconnect(fails)
         self._testIsClean(a_signal)
         self._testIsClean(a_signal)