From 40c593e5f589bed5ff743a9e4f27fbe5622dc567 Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Mon, 29 Nov 2010 10:50:34 +0100 Subject: [PATCH] Started work on support for transparent proxies for the debug hack --- jinja2/debug.py | 56 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/jinja2/debug.py b/jinja2/debug.py index eb15456..e8492cd 100644 --- a/jinja2/debug.py +++ b/jinja2/debug.py @@ -12,9 +12,16 @@ """ import sys import traceback +from types import TracebackType from jinja2.utils import CodeType, missing, internal_code from jinja2.exceptions import TemplateSyntaxError +# on pypy we can take advantage of transparent proxies +try: + from __pypy__ import tproxy +except ImportError: + tproxy = None + # how does the raise helper look like? try: @@ -30,6 +37,7 @@ class TracebackFrameProxy(object): def __init__(self, tb): self.tb = tb + self._tb_next = None def _set_tb_next(self, next): if tb_set_next is not None: @@ -50,6 +58,15 @@ class TracebackFrameProxy(object): return getattr(self.tb, name) +def make_frame_proxy(frame): + proxy = TracebackFrameProxy(frame) + if tproxy is None: + return proxy + def operation_handler(operation, *args, **kwargs): + return getattr(proxy, operation)(*args, **kwargs) + return tproxy(TracebackType, operation_handler) + + class ProcessedTraceback(object): """Holds a Jinja preprocessed traceback for priting or reraising.""" @@ -59,8 +76,7 @@ class ProcessedTraceback(object): self.exc_value = exc_value self.frames = frames - def chain_frames(self): - """Chains the frames. Requires ctypes or the debugsupport extension.""" + # newly concatenate the frames (which are proxies) prev_tb = None for tb in self.frames: if prev_tb is not None: @@ -95,7 +111,12 @@ class ProcessedTraceback(object): @property def standard_exc_info(self): """Standard python exc_info for re-raising""" - return self.exc_type, self.exc_value, self.frames[0].tb + tb = self.frames[0] + # the frame will be an actual traceback (or transparent proxy) if + # we are on pypy or a python implementation with support for tproxy + if type(tb) is not TracebackType: + tb = tb.tb + return self.exc_type, self.exc_value, tb def make_traceback(exc_info, source_hint=None): @@ -152,7 +173,7 @@ def translate_exception(exc_info, initial_skip=0): tb = fake_exc_info(exc_info[:2] + (tb,), template.filename, lineno)[2] - frames.append(TracebackFrameProxy(tb)) + frames.append(make_frame_proxy(tb)) tb = next # if we don't have any exceptions in the frames left, we have to @@ -161,10 +182,7 @@ def translate_exception(exc_info, initial_skip=0): if not frames: raise exc_info[0], exc_info[1], exc_info[2] - traceback = ProcessedTraceback(exc_info[0], exc_info[1], frames) - if tb_set_next is not None: - traceback.chain_frames() - return traceback + return ProcessedTraceback(exc_info[0], exc_info[1], frames) def fake_exc_info(exc_info, filename, lineno): @@ -239,7 +257,8 @@ def fake_exc_info(exc_info, filename, lineno): def _init_ugly_crap(): """This function implements a few ugly things so that we can patch the traceback objects. The function returned allows resetting `tb_next` on - any python traceback object. + any python traceback object. Do not attempt to use this on non cpython + interpreters """ import ctypes from types import TracebackType @@ -297,12 +316,15 @@ def _init_ugly_crap(): return tb_set_next -# try to get a tb_set_next implementation -try: - from jinja2._debugsupport import tb_set_next -except ImportError: +# try to get a tb_set_next implementation if we don't have transparent +# proxies. +tb_set_next = None +if tproxy is None: try: - tb_set_next = _init_ugly_crap() - except: - tb_set_next = None -del _init_ugly_crap + from jinja2._debugsupport import tb_set_next + except ImportError: + try: + tb_set_next = _init_ugly_crap() + except: + pass + del _init_ugly_crap -- 2.26.2