From ebb0279f4a7a7155c44c09506bbe5b1f9acc83a2 Mon Sep 17 00:00:00 2001 From: Unai Zalakain Date: Wed, 30 Oct 2013 12:11:04 +0100 Subject: [PATCH] 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. --- django/dispatch/dispatcher.py | 5 ++++- docs/releases/1.8.txt | 4 +++- docs/topics/signals.txt | 5 +++++ tests/dispatch/tests/test_dispatcher.py | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py index ba97077ce5..20048f5c55 100644 --- a/django/dispatch/dispatcher.py +++ b/django/dispatch/dispatcher.py @@ -220,7 +220,8 @@ class Signal(object): If any receiver raises an error (specifically any subclass of Exception), the error instance is returned as the result for that - receiver. + receiver. The traceback is always attached to the error at + ``__traceback__``. """ responses = [] if not self.receivers or self.sender_receivers_cache.get(sender) is NO_RECEIVERS: @@ -232,6 +233,8 @@ class Signal(object): try: response = receiver(signal=self, sender=sender, **named) except Exception as err: + if not hasattr(err, '__traceback__'): + err.__traceback__ = sys.exc_info()[2] responses.append((receiver, err)) else: responses.append((receiver, response)) diff --git a/docs/releases/1.8.txt b/docs/releases/1.8.txt index aa39fb2b7c..94a4f3ed74 100644 --- a/docs/releases/1.8.txt +++ b/docs/releases/1.8.txt @@ -153,7 +153,9 @@ Models Signals ^^^^^^^ -* ... +* Exceptions from the ``(receiver, exception)`` tuples returned by + :meth:`Signal.send_robust() ` now have + their traceback attached as a ``__traceback__`` attribute. Templates ^^^^^^^^^ diff --git a/docs/topics/signals.txt b/docs/topics/signals.txt index 346d47d179..fb83258c9b 100644 --- a/docs/topics/signals.txt +++ b/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 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 ===================== diff --git a/tests/dispatch/tests/test_dispatcher.py b/tests/dispatch/tests/test_dispatcher.py index 05b375f7d6..1bfa48aa80 100644 --- a/tests/dispatch/tests/test_dispatcher.py +++ b/tests/dispatch/tests/test_dispatcher.py @@ -3,6 +3,7 @@ import sys import time import unittest import weakref +from types import TracebackType from django.dispatch import Signal, receiver @@ -134,6 +135,8 @@ class DispatcherTests(unittest.TestCase): err = result[0][1] self.assertIsInstance(err, ValueError) self.assertEqual(err.args, ('this',)) + self.assertTrue(hasattr(err, '__traceback__')) + self.assertTrue(isinstance(err.__traceback__, TracebackType)) a_signal.disconnect(fails) self._testIsClean(a_signal)