summaryrefslogtreecommitdiffstats
path: root/module/lib/jinja2/debug.py
diff options
context:
space:
mode:
Diffstat (limited to 'module/lib/jinja2/debug.py')
-rw-r--r--module/lib/jinja2/debug.py103
1 files changed, 66 insertions, 37 deletions
diff --git a/module/lib/jinja2/debug.py b/module/lib/jinja2/debug.py
index eb15456d1..815cc18a4 100644
--- a/module/lib/jinja2/debug.py
+++ b/module/lib/jinja2/debug.py
@@ -12,13 +12,21 @@
"""
import sys
import traceback
-from jinja2.utils import CodeType, missing, internal_code
+from types import TracebackType
+from jinja2.utils import missing, internal_code
from jinja2.exceptions import TemplateSyntaxError
+from jinja2._compat import iteritems, reraise, code_type
+
+# 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:
- exec "raise TypeError, 'foo'"
+ exec("raise TypeError, 'foo'")
except SyntaxError:
raise_helper = 'raise __jinja_exception__[1]'
except TypeError:
@@ -30,17 +38,22 @@ 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:
- tb_set_next(self.tb, next and next.tb or None)
- self._tb_next = next
-
- def _get_tb_next(self):
+ @property
+ def tb_next(self):
return self._tb_next
- tb_next = property(_get_tb_next, _set_tb_next)
- del _get_tb_next, _set_tb_next
+ def set_next(self, next):
+ if tb_set_next is not None:
+ try:
+ tb_set_next(self.tb, next and next.tb or None)
+ except Exception:
+ # this function can fail due to all the hackery it does
+ # on various python implementations. We just catch errors
+ # down and ignore them if necessary.
+ pass
+ self._tb_next = next
@property
def is_jinja_frame(self):
@@ -50,8 +63,22 @@ 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):
+ if operation in ('__getattribute__', '__getattr__'):
+ return getattr(proxy, args[0])
+ elif operation == '__setattr__':
+ proxy.__setattr__(*args, **kwargs)
+ else:
+ return getattr(proxy, operation)(*args, **kwargs)
+ return tproxy(TracebackType, operation_handler)
+
+
class ProcessedTraceback(object):
- """Holds a Jinja preprocessed traceback for priting or reraising."""
+ """Holds a Jinja preprocessed traceback for printing or reraising."""
def __init__(self, exc_type, exc_value, frames):
assert frames, 'no frames for this traceback?'
@@ -59,14 +86,13 @@ 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:
- prev_tb.tb_next = tb
+ prev_tb.set_next(tb)
prev_tb = tb
- prev_tb.tb_next = None
+ prev_tb.set_next(None)
def render_as_text(self, limit=None):
"""Return a string with the traceback."""
@@ -95,7 +121,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):
@@ -128,7 +159,7 @@ def translate_exception(exc_info, initial_skip=0):
frames = []
# skip some internal frames if wanted
- for x in xrange(initial_skip):
+ for x in range(initial_skip):
if tb is not None:
tb = tb.tb_next
initial_tb = tb
@@ -152,19 +183,16 @@ 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
# reraise it unchanged.
# XXX: can we backup here? when could this happen?
if not frames:
- raise exc_info[0], exc_info[1], exc_info[2]
+ reraise(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):
@@ -179,7 +207,7 @@ def fake_exc_info(exc_info, filename, lineno):
locals = ctx.get_all()
else:
locals = {}
- for name, value in real_locals.iteritems():
+ for name, value in iteritems(real_locals):
if name.startswith('l_') and value is not missing:
locals[name[2:]] = value
@@ -217,17 +245,17 @@ def fake_exc_info(exc_info, filename, lineno):
location = 'block "%s"' % function[6:]
else:
location = 'template'
- code = CodeType(0, code.co_nlocals, code.co_stacksize,
- code.co_flags, code.co_code, code.co_consts,
- code.co_names, code.co_varnames, filename,
- location, code.co_firstlineno,
- code.co_lnotab, (), ())
+ code = code_type(0, code.co_nlocals, code.co_stacksize,
+ code.co_flags, code.co_code, code.co_consts,
+ code.co_names, code.co_varnames, filename,
+ location, code.co_firstlineno,
+ code.co_lnotab, (), ())
except:
pass
# execute the code and catch the new traceback
try:
- exec code in globals, locals
+ exec(code, globals, locals)
except:
exc_info = sys.exc_info()
new_tb = exc_info[2].tb_next
@@ -239,7 +267,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 +326,12 @@ 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
+ pass
+ del _init_ugly_crap