"""
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:
def __init__(self, tb):
self.tb = tb
+ self._tb_next = None
def _set_tb_next(self, next):
if tb_set_next is not None:
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."""
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:
@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):
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
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):
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
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