Started refactoring of debugging system for better AppEngine/Pylons support.

--HG--
branch : trunk
extra : rebase_source : 30b87a402e0847f95eaf277d0fc50e1a63177d5b
diff --git a/jinja2/environment.py b/jinja2/environment.py
index 23bf24b..c2fee16 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -24,6 +24,10 @@
 # for direct template usage we have up to ten living environments
 _spontaneous_environments = LRUCache(10)
 
+# the function to create jinja traceback objects.  This is dynamically
+# imported on the first exception in the exception handler.
+_make_traceback = None
+
 
 def get_spontaneous_environment(*args):
     """Return a new spontaneous environment.  A spontaneous environment is an
@@ -196,6 +200,9 @@
     #: must not be modified
     shared = False
 
+    exception_handler = None
+    exception_formatter = None
+
     def __init__(self,
                  block_start_string=BLOCK_START_STRING,
                  block_end_string=BLOCK_END_STRING,
@@ -362,9 +369,7 @@
         try:
             return Parser(self, source, name, filename).parse()
         except TemplateSyntaxError, e:
-            from jinja2.debug import translate_syntax_error
-            exc_type, exc_value, tb = translate_syntax_error(e, source)
-            raise exc_type, exc_value, tb
+            self.handle_exception(sys.exc_info(), source_hint=source)
 
     def lex(self, source, name=None, filename=None):
         """Lex the given sourcecode and return a generator that yields
@@ -380,9 +385,7 @@
         try:
             return self.lexer.tokeniter(source, name, filename)
         except TemplateSyntaxError, e:
-            from jinja2.debug import translate_syntax_error
-            exc_type, exc_value, tb = translate_syntax_error(e, source)
-            raise exc_type, exc_value, tb
+            self.handle_exception(sys.exc_info(), source_hint=source)
 
     def preprocess(self, source, name=None, filename=None):
         """Preprocesses the source with all extensions.  This is automatically
@@ -473,6 +476,23 @@
         template = self.from_string(nodes.Template(body, lineno=1))
         return TemplateExpression(template, undefined_to_none)
 
+    def handle_exception(self, exc_info=None, rendered=False, source_hint=None):
+        """Exception handling helper.  This is used internally to either raise
+        rewritten exceptions or return a rendered traceback for the template.
+        """
+        global _make_traceback
+        if exc_info is None:
+            exc_info = sys.exc_info()
+        if _make_traceback is None:
+            from jinja2.debug import make_traceback as _make_traceback
+        traceback = _make_traceback(exc_info, source_hint)
+        if rendered and self.exception_formatter is not None:
+            return self.exception_formatter(traceback)
+        if self.exception_handler is not None:
+            self.exception_handler(traceback)
+        exc_type, exc_value, tb = traceback.standard_exc_info
+        raise exc_type, exc_value, tb
+
     def join_path(self, template, parent):
         """Join a template with the parent.  By default all the lookups are
         relative to the loader root so this method returns the `template`
@@ -625,9 +645,7 @@
         try:
             return concat(self.root_render_func(self.new_context(vars)))
         except:
-            from jinja2.debug import translate_exception
-            exc_type, exc_value, tb = translate_exception(sys.exc_info())
-            raise exc_type, exc_value, tb
+            return self.environment.handle_exception(sys.exc_info(), True)
 
     def stream(self, *args, **kwargs):
         """Works exactly like :meth:`generate` but returns a
@@ -648,9 +666,7 @@
             for event in self.root_render_func(self.new_context(vars)):
                 yield event
         except:
-            from jinja2.debug import translate_exception
-            exc_type, exc_value, tb = translate_exception(sys.exc_info())
-            raise exc_type, exc_value, tb
+            yield self.environment.handle_exception(sys.exc_info(), True)
 
     def new_context(self, vars=None, shared=False, locals=None):
         """Create a new :class:`Context` for this template.  The vars