Rewrite the current exception to replace any tracebacks from within compiled template code with tracebacks that look like they came from the template source. This must be called within an ``except`` block. :param source: For ``TemplateSyntaxError``, the original source if k
(source: t.Optional[str] = None)
| 12 | |
| 13 | |
| 14 | def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: |
| 15 | class="st">"""Rewrite the current exception to replace any tracebacks from |
| 16 | within compiled template code with tracebacks that look like they |
| 17 | came from the template source. |
| 18 | |
| 19 | This must be called within an ``except`` block. |
| 20 | |
| 21 | :param source: For ``TemplateSyntaxError``, the original source if |
| 22 | known. |
| 23 | :return: The original exception with the rewritten traceback. |
| 24 | class="st">""" |
| 25 | _, exc_value, tb = sys.exc_info() |
| 26 | exc_value = t.cast(BaseException, exc_value) |
| 27 | tb = t.cast(TracebackType, tb) |
| 28 | |
| 29 | if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: |
| 30 | exc_value.translated = True |
| 31 | exc_value.source = source |
| 32 | class="cm"># Remove the old traceback, otherwise the frames from the |
| 33 | class="cm"># compiler still show up. |
| 34 | exc_value.with_traceback(None) |
| 35 | class="cm"># Outside of runtime, so the frame isn't executing template |
| 36 | class="cm"># code, but it still needs to point at the template. |
| 37 | tb = fake_traceback( |
| 38 | exc_value, None, exc_value.filename or class="st">"<unknown>", exc_value.lineno |
| 39 | ) |
| 40 | else: |
| 41 | class="cm"># Skip the frame for the render function. |
| 42 | tb = tb.tb_next |
| 43 | |
| 44 | stack = [] |
| 45 | |
| 46 | class="cm"># Build the stack of traceback object, replacing any in template |
| 47 | class="cm"># code with the source file and line information. |
| 48 | while tb is not None: |
| 49 | class="cm"># Skip frames decorated with @internalcode. These are internal |
| 50 | class="cm"># calls that aren't useful in template debugging output. |
| 51 | if tb.tb_frame.f_code in internal_code: |
| 52 | tb = tb.tb_next |
| 53 | continue |
| 54 | |
| 55 | template = tb.tb_frame.f_globals.get(class="st">"__jinja_template__") |
| 56 | |
| 57 | if template is not None: |
| 58 | lineno = template.get_corresponding_lineno(tb.tb_lineno) |
| 59 | fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) |
| 60 | stack.append(fake_tb) |
| 61 | else: |
| 62 | stack.append(tb) |
| 63 | |
| 64 | tb = tb.tb_next |
| 65 | |
| 66 | tb_next = None |
| 67 | |
| 68 | class="cm"># Assign tb_next in reverse to avoid circular references. |
| 69 | for tb in reversed(stack): |
| 70 | tb.tb_next = tb_next |
| 71 | tb_next = tb |
no test coverage detected