diff --git a/django/dispatch/dispatcher.py b/django/dispatch/dispatcher.py
index ed9da57..b2abd21 100644
a
|
b
|
|
| 1 | import sys |
1 | 2 | import weakref |
2 | 3 | import threading |
3 | 4 | |
… |
… |
class Signal(object):
|
173 | 174 | responses.append((receiver, response)) |
174 | 175 | return responses |
175 | 176 | |
176 | | def send_robust(self, sender, **named): |
| 177 | def send_robust(self, sender, exc_info=False, **named): |
177 | 178 | """ |
178 | 179 | Send signal from sender to all connected receivers catching errors. |
179 | 180 | |
… |
… |
class Signal(object):
|
184 | 185 | registered with a connect if you actually want something to |
185 | 186 | occur). |
186 | 187 | |
| 188 | exc_info |
| 189 | If an exception occurs in a receiver, return a triple (type, |
| 190 | exception, traceback) as the response instead of just an exception |
| 191 | instance. |
| 192 | |
187 | 193 | named |
188 | 194 | Named arguments which will be passed to receivers. These |
189 | 195 | arguments must be a subset of the argument names defined in |
… |
… |
class Signal(object):
|
194 | 200 | |
195 | 201 | If any receiver raises an error (specifically any subclass of |
196 | 202 | Exception), the error instance is returned as the result for that |
197 | | receiver. |
| 203 | receiver. If exc_info is True, a triple that includes the exception type, |
| 204 | the exception instance, and a traceback (type, exception, traceback) will |
| 205 | be returned instead of just the error instance. |
198 | 206 | """ |
199 | 207 | responses = [] |
200 | 208 | if not self.receivers: |
… |
… |
class Signal(object):
|
206 | 214 | try: |
207 | 215 | response = receiver(signal=self, sender=sender, **named) |
208 | 216 | except Exception, err: |
209 | | responses.append((receiver, err)) |
| 217 | if exc_info: |
| 218 | responses.append((receiver, sys.exc_info())) |
| 219 | else: |
| 220 | responses.append((receiver, err)) |
210 | 221 | else: |
211 | 222 | responses.append((receiver, response)) |
212 | 223 | return responses |
diff --git a/docs/topics/signals.txt b/docs/topics/signals.txt
index df4b58b..9450749 100644
a
|
b
|
Sending signals
|
231 | 231 | There are two ways to send send signals in Django. |
232 | 232 | |
233 | 233 | .. method:: Signal.send(sender, **kwargs) |
234 | | .. method:: Signal.send_robust(sender, **kwargs) |
| 234 | .. method:: Signal.send_robust(sender, exc_info=True, **kwargs) |
235 | 235 | |
236 | 236 | To send a signal, call either :meth:`Signal.send` or :meth:`Signal.send_robust`. |
237 | 237 | You must provide the ``sender`` argument, and may provide as many other keyword |
… |
… |
be notified of a signal in the face of an error.
|
260 | 260 | ``send_robust()`` catches all errors derived from Python's ``Exception`` class, |
261 | 261 | and ensures all receivers are notified of the signal. If an error occurs, the |
262 | 262 | error instance is returned in the tuple pair for the receiver that raised the error. |
| 263 | If ``exc_info`` is ``True``, a triple containing the error type, error instance and |
| 264 | traceback is returned instead of the error instance. This is identical to the value |
| 265 | returned by calling ``sys.exc_info()`` at the point of the exception and may be |
| 266 | useful for logging or debugging purposes. |
| 267 | |
| 268 | |
| 269 | .. versionchanged:: 1.4 |
| 270 | A triple containing the exception type, the exception instance and a full traceback |
| 271 | can be returned as the response (instead of just a simple error instance) for a receiver that |
| 272 | raises an exception by setting ``exc_info`` to ``True`` when calling |
| 273 | ``send_robust()``. |
263 | 274 | |
264 | 275 | Disconnecting signals |
265 | 276 | ===================== |
diff --git a/tests/regressiontests/dispatch/tests/test_dispatcher.py b/tests/regressiontests/dispatch/tests/test_dispatcher.py
index a16d8e2..44c4cc0 100644
a
|
b
|
|
1 | 1 | import gc |
2 | 2 | import sys |
| 3 | from types import TracebackType |
3 | 4 | |
4 | 5 | from django.dispatch import Signal |
5 | 6 | from django.utils import unittest |
… |
… |
class DispatcherTests(unittest.TestCase):
|
98 | 99 | a_signal.connect(fails) |
99 | 100 | result = a_signal.send_robust(sender=self, val="test") |
100 | 101 | err = result[0][1] |
| 102 | self.assertEqual(len(result[0]), 2) |
101 | 103 | self.assertTrue(isinstance(err, ValueError)) |
102 | 104 | self.assertEqual(err.args, ('this',)) |
| 105 | |
| 106 | result = a_signal.send_robust(sender=self, exc_info=True, val="test") |
| 107 | exc_info_triple = result[0][1] |
| 108 | self.assertEqual(exc_info_triple[0], ValueError) |
| 109 | self.assertTrue(isinstance(exc_info_triple[1], ValueError)) |
| 110 | self.assertTrue(isinstance(exc_info_triple[2], TracebackType)) |
103 | 111 | a_signal.disconnect(fails) |
104 | 112 | self._testIsClean(a_signal) |
105 | 113 | |