Ticket #16245: add_traceback_to_send_robust.v2.diff

File add_traceback_to_send_robust.v2.diff, 4.5 KB (added by Jim Dalton, 13 years ago)
  • docs/topics/signals.txt

     
    231231There are two ways to send send signals in Django.
    232232
    233233.. method:: Signal.send(sender, **kwargs)
    234 .. method:: Signal.send_robust(sender, **kwargs)
     234.. method:: Signal.send_robust(sender, append_traceback=True, **kwargs)
    235235
    236236To send a signal, call either :meth:`Signal.send` or :meth:`Signal.send_robust`.
    237237You must provide the ``sender`` argument, and may provide as many other keyword
     
    260260``send_robust()`` catches all errors derived from Python's ``Exception`` class,
    261261and ensures all receivers are notified of the signal. If an error occurs, the
    262262error instance is returned in the tuple pair for the receiver that raised the error.
     263If ``append_traceback`` is True, a ``traceback`` object with the call stack at the
     264point where the exception occurred will also be added to the tuple. In that case,
     265the tuple response would look like ``(receiver, error, traceback)``.
    263266
     267
     268.. versionchanged:: 1.4
     269   A ``traceback`` object can be appended to the tuple response for a receiver that
     270   raises an exception by setting ``append_traceback`` to ``True`` when calling
     271   ``send_robust()``.
     272
    264273Disconnecting signals
    265274=====================
    266275
  • django/dispatch/dispatcher.py

     
     1import sys
    12import weakref
    23import threading
    34
     
    173174            responses.append((receiver, response))
    174175        return responses
    175176
    176     def send_robust(self, sender, **named):
     177    def send_robust(self, sender, append_traceback=False, **named):
    177178        """
    178179        Send signal from sender to all connected receivers catching errors.
    179180
     
    184185                registered with a connect if you actually want something to
    185186                occur).
    186187
     188            append_traceback
     189                If an exception occurs in a receiver, append a traceback object
     190                to the tuple result for that receiver.
     191
    187192            named
    188193                Named arguments which will be passed to receivers. These
    189194                arguments must be a subset of the argument names defined in
     
    194199
    195200        If any receiver raises an error (specifically any subclass of
    196201        Exception), the error instance is returned as the result for that
    197         receiver.
     202        receiver. If append_traceback is True, a traceback object will
     203        also be included in the result, i.e. (receiver, error, traceback).
    198204        """
    199205        responses = []
    200206        if not self.receivers:
     
    206212            try:
    207213                response = receiver(signal=self, sender=sender, **named)
    208214            except Exception, err:
    209                 responses.append((receiver, err))
     215                if append_traceback:
     216                    # Wrap traceback in try...finally to prevent circular reference
     217                    # See warning at http://docs.python.org/library/sys.html#sys.exc_info
     218                    try:
     219                        traceback = sys.exc_info()[2]
     220                        responses.append((receiver, err, traceback))
     221                    finally:
     222                        del traceback
     223                else:
     224                    responses.append((receiver, err))
    210225            else:
    211226                responses.append((receiver, response))
    212227        return responses
  • tests/regressiontests/dispatch/tests/test_dispatcher.py

     
    11import gc
    22import sys
     3from types import TracebackType
    34
    45from django.dispatch import Signal
    56from django.utils import unittest
     
    9899        a_signal.connect(fails)
    99100        result = a_signal.send_robust(sender=self, val="test")
    100101        err = result[0][1]
     102        self.assertEqual(len(result[0]), 2)
    101103        self.assertTrue(isinstance(err, ValueError))
    102104        self.assertEqual(err.args, ('this',))
     105       
     106        result = a_signal.send_robust(sender=self, append_traceback=True, val="test")
     107        traceback = result[0][2]
     108        self.assertTrue(isinstance(traceback, TracebackType))
    103109        a_signal.disconnect(fails)
    104110        self._testIsClean(a_signal)
    105111
Back to Top