diff options
Diffstat (limited to 'django/views/debug.py')
| -rw-r--r-- | django/views/debug.py | 55 |
1 files changed, 52 insertions, 3 deletions
diff --git a/django/views/debug.py b/django/views/debug.py index d0235f4bd4..c2a290573a 100644 --- a/django/views/debug.py +++ b/django/views/debug.py @@ -479,8 +479,29 @@ class ExceptionReporter(object): return lower_bound, pre_context, context_line, post_context def get_traceback_frames(self): + def explicit_or_implicit_cause(exc_value): + explicit = getattr(exc_value, '__cause__', None) + implicit = getattr(exc_value, '__context__', None) + return explicit or implicit + + # Get the exception and all its causes + exceptions = [] + exc_value = self.exc_value + while exc_value: + exceptions.append(exc_value) + exc_value = explicit_or_implicit_cause(exc_value) + frames = [] - tb = self.tb + # No exceptions were supplied to ExceptionReporter + if not exceptions: + return frames + + # In case there's just one exception (always in Python 2, + # sometimes in Python 3), take the traceback from self.tb (Python 2 + # doesn't have a __traceback__ attribute on Exception) + exc_value = exceptions.pop() + tb = self.tb if not exceptions else exc_value.__traceback__ + while tb is not None: # Support for __traceback_hide__ which is used by a few libraries # to hide internal frames. @@ -497,6 +518,8 @@ class ExceptionReporter(object): ) if pre_context_lineno is not None: frames.append({ + 'exc_cause': explicit_or_implicit_cause(exc_value), + 'exc_cause_explicit': getattr(exc_value, '__cause__', True), 'tb': tb, 'type': 'django' if module_name.startswith('django.') else 'user', 'filename': filename, @@ -509,7 +532,14 @@ class ExceptionReporter(object): 'post_context': post_context, 'pre_context_lineno': pre_context_lineno + 1, }) - tb = tb.tb_next + + # If the traceback for current exception is consumed, try the + # other exception. + if not tb.tb_next and exceptions: + exc_value = exceptions.pop() + tb = exc_value.__traceback__ + else: + tb = tb.tb_next return frames @@ -838,6 +868,15 @@ TECHNICAL_500_TEMPLATE = (""" <div id="browserTraceback"> <ul class="traceback"> {% for frame in frames %} + {% ifchanged frame.exc_cause %}{% if frame.exc_cause %} + <li><h3> + {% if frame.exc_cause_explicit %} + The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception: + {% else %} + During handling of the above exception ({{ frame.exc_cause }}), another exception occurred: + {% endif %} + </h3></li> + {% endif %}{% endifchanged %} <li class="frame {{ frame.type }}"> <code>{{ frame.filename|escape }}</code> in <code>{{ frame.function|escape }}</code> @@ -1123,7 +1162,17 @@ In template {{ template_info.name }}, error at line {{ template_info.line }} {{ source_line.0 }} : {{ source_line.1 }} {% endifequal %}{% endfor %}{% endif %}{% if frames %} Traceback: -{% for frame in frames %}File "{{ frame.filename }}" in {{ frame.function }} +{% for frame in frames %} +{% ifchanged frame.exc_cause %} + {% if frame.exc_cause %} + {% if frame.exc_cause_explicit %} + The above exception ({{ frame.exc_cause }}) was the direct cause of the following exception: + {% else %} + During handling of the above exception ({{ frame.exc_cause }}), another exception occurred: + {% endif %} + {% endif %} +{% endifchanged %} +File "{{ frame.filename }}" in {{ frame.function }} {% if frame.context_line %} {{ frame.lineno }}. {{ frame.context_line }}{% endif %} {% endfor %} {% if exception_type %}Exception Type: {{ exception_type }}{% if request %} at {{ request.path_info }}{% endif %} |
