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

--HG--
branch : trunk
diff --git a/jinja2/environment.py b/jinja2/environment.py
index c7f311e..803e7a8 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
@@ -190,6 +194,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,
@@ -354,9 +361,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
@@ -372,9 +377,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
@@ -465,6 +468,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`
@@ -616,9 +636,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
@@ -639,9 +657,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