Skip to content

Commit

Permalink
Started work on support for transparent proxies for the debug hack
Browse files Browse the repository at this point in the history
  • Loading branch information
mitsuhiko committed Nov 29, 2010
1 parent 6a3e95d commit 40c593e
Showing 1 changed file with 39 additions and 17 deletions.
56 changes: 39 additions & 17 deletions jinja2/debug.py
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -50,6 +58,15 @@ def __getattr__(self, name):
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."""

Expand All @@ -59,8 +76,7 @@ def __init__(self, exc_type, exc_value, frames):
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:
Expand Down Expand Up @@ -95,7 +111,12 @@ def exc_info(self):
@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):
Expand Down Expand Up @@ -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
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -297,12 +316,15 @@ def tb_set_next(tb, next):
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

0 comments on commit 40c593e

Please sign in to comment.