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.
This commit is contained in:
Unai Zalakain 2013-10-30 12:11:04 +01:00 committed by Tim Graham
parent 79e9da3d1e
commit ebb0279f4a
4 changed files with 15 additions and 2 deletions

View File

@ -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))

View File

@ -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
^^^^^^^^^ ^^^^^^^^^

View File

@ -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
===================== =====================

View File

@ -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)