Fixed indentation.
[libfirm] / scripts / jinja2 / environment.py
index 4a9c9d1..7a9a59f 100644 (file)
@@ -5,9 +5,10 @@
 
     Provides a class that holds runtime and parsing time options.
 
-    :copyright: 2008 by Armin Ronacher.
+    :copyright: (c) 2010 by the Jinja Team.
     :license: BSD, see LICENSE for more details.
 """
+import os
 import sys
 from jinja2 import nodes
 from jinja2.defaults import *
@@ -15,15 +16,20 @@ from jinja2.lexer import get_lexer, TokenStream
 from jinja2.parser import Parser
 from jinja2.optimizer import optimize
 from jinja2.compiler import generate
-from jinja2.runtime import Undefined, Context
-from jinja2.exceptions import TemplateSyntaxError
+from jinja2.runtime import Undefined, new_context
+from jinja2.exceptions import TemplateSyntaxError, TemplateNotFound, \
+     TemplatesNotFound
 from jinja2.utils import import_string, LRUCache, Markup, missing, \
-     concat, consume
+     concat, consume, internalcode, _encode_filename
 
 
 # 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
@@ -53,7 +59,7 @@ def create_cache(size):
 def copy_cache(cache):
     """Create an empty copy of the given cache."""
     if cache is None:
-        return Noe
+        return None
     elif type(cache) is dict:
         return {}
     return LRUCache(cache.capacity)
@@ -118,6 +124,12 @@ class Environment(object):
             If given and a string, this will be used as prefix for line based
             statements.  See also :ref:`line-statements`.
 
+        `line_comment_prefix`
+            If given and a string, this will be used as prefix for line based
+            based comments.  See also :ref:`line-statements`.
+
+            .. versionadded:: 2.2
+
         `trim_blocks`
             If this is set to ``True`` the first newline after a block is
             removed (block, not variable tag!).  Defaults to `False`.
@@ -141,13 +153,20 @@ class Environment(object):
             undefined values in the template.
 
         `finalize`
-            A callable that finalizes the variable.  Per default no finalizing
-            is applied.
+            A callable that can be used to process the result of a variable
+            expression before it is output.  For example one can convert
+            `None` implicitly into an empty string here.
 
         `autoescape`
-            If set to true the XML/HTML autoescaping feature is enabled.
-            For more details about auto escaping see
-            :class:`~jinja2.utils.Markup`.
+            If set to true the XML/HTML autoescaping feature is enabled by
+            default.  For more details about auto escaping see
+            :class:`~jinja2.utils.Markup`.  As of Jinja 2.4 this can also
+            be a callable that is passed the template name and has to
+            return `True` or `False` depending on autoescape should be
+            enabled by default.
+
+            .. versionchanged:: 2.4
+               `autoescape` can now be a function
 
         `loader`
             The template loader for this environment.
@@ -177,11 +196,12 @@ class Environment(object):
 
     #: if this environment is sandboxed.  Modifying this variable won't make
     #: the environment sandboxed though.  For a real sandboxed environment
-    #: have a look at jinja2.sandbox
+    #: have a look at jinja2.sandbox.  This flag alone controls the code
+    #: generation by the compiler.
     sandboxed = False
 
     #: True if the environment is just an overlay
-    overlay = False
+    overlayed = False
 
     #: the environment this environment is linked to if it is an overlay
     linked_to = None
@@ -190,6 +210,10 @@ class Environment(object):
     #: must not be modified
     shared = False
 
+    #: these are currently EXPERIMENTAL undocumented features.
+    exception_handler = None
+    exception_formatter = None
+
     def __init__(self,
                  block_start_string=BLOCK_START_STRING,
                  block_end_string=BLOCK_END_STRING,
@@ -198,6 +222,7 @@ class Environment(object):
                  comment_start_string=COMMENT_START_STRING,
                  comment_end_string=COMMENT_END_STRING,
                  line_statement_prefix=LINE_STATEMENT_PREFIX,
+                 line_comment_prefix=LINE_COMMENT_PREFIX,
                  trim_blocks=TRIM_BLOCKS,
                  newline_sequence=NEWLINE_SEQUENCE,
                  extensions=(),
@@ -228,6 +253,7 @@ class Environment(object):
         self.comment_start_string = comment_start_string
         self.comment_end_string = comment_end_string
         self.line_statement_prefix = line_statement_prefix
+        self.line_comment_prefix = line_comment_prefix
         self.trim_blocks = trim_blocks
         self.newline_sequence = newline_sequence
 
@@ -254,6 +280,13 @@ class Environment(object):
 
         _environment_sanity_check(self)
 
+    def add_extension(self, extension):
+        """Adds an extension after the environment was created.
+
+        .. versionadded:: 2.5
+        """
+        self.extensions.update(load_extensions(self, [extension]))
+
     def extend(self, **attributes):
         """Add the items to the instance of the environment if they do not exist
         yet.  This is used by :ref:`extensions <writing-extensions>` to register
@@ -266,14 +299,14 @@ class Environment(object):
     def overlay(self, block_start_string=missing, block_end_string=missing,
                 variable_start_string=missing, variable_end_string=missing,
                 comment_start_string=missing, comment_end_string=missing,
-                line_statement_prefix=missing, trim_blocks=missing,
-                extensions=missing, optimized=missing, undefined=missing,
-                finalize=missing, autoescape=missing, loader=missing,
-                cache_size=missing, auto_reload=missing,
+                line_statement_prefix=missing, line_comment_prefix=missing,
+                trim_blocks=missing, extensions=missing, optimized=missing,
+                undefined=missing, finalize=missing, autoescape=missing,
+                loader=missing, cache_size=missing, auto_reload=missing,
                 bytecode_cache=missing):
         """Create a new overlay environment that shares all the data with the
-        current environment except of cache and the overriden attributes.
-        Extensions cannot be removed for a overlayed environment.  A overlayed
+        current environment except of cache and the overridden attributes.
+        Extensions cannot be removed for an overlayed environment.  An overlayed
         environment automatically gets all the extensions of the environment it
         is linked to plus optional extra extensions.
 
@@ -287,7 +320,7 @@ class Environment(object):
 
         rv = object.__new__(self.__class__)
         rv.__dict__.update(self.__dict__)
-        rv.overlay = True
+        rv.overlayed = True
         rv.linked_to = self
 
         for key, value in args.iteritems():
@@ -303,12 +336,17 @@ class Environment(object):
         for key, value in self.extensions.iteritems():
             rv.extensions[key] = value.bind(rv)
         if extensions is not missing:
-            rv.extensions.update(load_extensions(extensions))
+            rv.extensions.update(load_extensions(rv, extensions))
 
         return _environment_sanity_check(rv)
 
     lexer = property(get_lexer, doc="The lexer for this environment.")
 
+    def iter_extensions(self):
+        """Iterates over the extensions by priority."""
+        return iter(sorted(self.extensions.values(),
+                           key=lambda x: x.priority))
+
     def getitem(self, obj, argument):
         """Get an item or attribute of an object but prefer the item."""
         try:
@@ -317,7 +355,7 @@ class Environment(object):
             if isinstance(argument, basestring):
                 try:
                     attr = str(argument)
-                except:
+                except Exception:
                     pass
                 else:
                     try:
@@ -339,6 +377,7 @@ class Environment(object):
         except (TypeError, LookupError, AttributeError):
             return self.undefined(obj=obj, name=attribute)
 
+    @internalcode
     def parse(self, source, name=None, filename=None):
         """Parse the sourcecode and return the abstract syntax tree.  This
         tree of nodes is used by the compiler to convert the template into
@@ -348,13 +387,15 @@ class Environment(object):
         If you are :ref:`developing Jinja2 extensions <writing-extensions>`
         this gives you a good overview of the node tree generated.
         """
-        if isinstance(filename, unicode):
-            filename = filename.encode('utf-8')
         try:
-            return Parser(self, source, name, filename).parse()
-        except TemplateSyntaxError, e:
-            e.source = source
-            raise e
+            return self._parse(source, name, filename)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        self.handle_exception(exc_info, source_hint=source)
+
+    def _parse(self, source, name, filename):
+        """Internal parsing function used by `parse` and `compile`."""
+        return Parser(self, source, name, _encode_filename(filename)).parse()
 
     def lex(self, source, name=None, filename=None):
         """Lex the given sourcecode and return a generator that yields
@@ -369,9 +410,9 @@ class Environment(object):
         source = unicode(source)
         try:
             return self.lexer.tokeniter(source, name, filename)
-        except TemplateSyntaxError, e:
-            e.source = source
-            raise e
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        self.handle_exception(exc_info, source_hint=source)
 
     def preprocess(self, source, name=None, filename=None):
         """Preprocesses the source with all extensions.  This is automatically
@@ -379,7 +420,7 @@ class Environment(object):
         because there you usually only want the actual source tokenized.
         """
         return reduce(lambda s, e: e.preprocess(s, name, filename),
-                      self.extensions.itervalues(), unicode(source))
+                      self.iter_extensions(), unicode(source))
 
     def _tokenize(self, source, name, filename=None, state=None):
         """Called by the parser to do the preprocessing and filtering
@@ -387,13 +428,31 @@ class Environment(object):
         """
         source = self.preprocess(source, name, filename)
         stream = self.lexer.tokenize(source, name, filename, state)
-        for ext in self.extensions.itervalues():
+        for ext in self.iter_extensions():
             stream = ext.filter_stream(stream)
             if not isinstance(stream, TokenStream):
                 stream = TokenStream(stream, name, filename)
         return stream
 
-    def compile(self, source, name=None, filename=None, raw=False):
+    def _generate(self, source, name, filename, defer_init=False):
+        """Internal hook that can be overriden to hook a different generate
+        method in.
+
+        .. versionadded:: 2.5
+        """
+        return generate(source, self, name, filename, defer_init=defer_init)
+
+    def _compile(self, source, filename):
+        """Internal hook that can be overriden to hook a different compile
+        method in.
+
+        .. versionadded:: 2.5
+        """
+        return compile(source, filename, 'exec')
+
+    @internalcode
+    def compile(self, source, name=None, filename=None, raw=False,
+                defer_init=False):
         """Compile a node or template source code.  The `name` parameter is
         the load name of the template after it was joined using
         :meth:`join_path` if necessary, not the filename on the file system.
@@ -405,19 +464,33 @@ class Environment(object):
         parameter is `True` the return value will be a string with python
         code equivalent to the bytecode returned otherwise.  This method is
         mainly used internally.
+
+        `defer_init` is use internally to aid the module code generator.  This
+        causes the generated code to be able to import without the global
+        environment variable to be set.
+
+        .. versionadded:: 2.4
+           `defer_init` parameter added.
         """
-        if isinstance(source, basestring):
-            source = self.parse(source, name, filename)
-        if self.optimized:
-            source = optimize(source, self)
-        source = generate(source, self, name, filename)
-        if raw:
-            return source
-        if filename is None:
-            filename = '<template>'
-        elif isinstance(filename, unicode):
-            filename = filename.encode('utf-8')
-        return compile(source, filename, 'exec')
+        source_hint = None
+        try:
+            if isinstance(source, basestring):
+                source_hint = source
+                source = self._parse(source, name, filename)
+            if self.optimized:
+                source = optimize(source, self)
+            source = self._generate(source, name, filename,
+                                    defer_init=defer_init)
+            if raw:
+                return source
+            if filename is None:
+                filename = '<template>'
+            else:
+                filename = _encode_filename(filename)
+            return self._compile(source, filename)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        self.handle_exception(exc_info, source_hint=source)
 
     def compile_expression(self, source, undefined_to_none=True):
         """A handy helper method that returns a callable that accepts keyword
@@ -445,22 +518,157 @@ class Environment(object):
         >>> env.compile_expression('var', undefined_to_none=False)()
         Undefined
 
-        **new in Jinja 2.1**
+        .. versionadded:: 2.1
         """
         parser = Parser(self, source, state='variable')
+        exc_info = None
         try:
             expr = parser.parse_expression()
             if not parser.stream.eos:
                 raise TemplateSyntaxError('chunk after expression',
                                           parser.stream.current.lineno,
                                           None, None)
-        except TemplateSyntaxError, e:
-            e.source = source
-            raise e
+            expr.set_environment(self)
+        except TemplateSyntaxError:
+            exc_info = sys.exc_info()
+        if exc_info is not None:
+            self.handle_exception(exc_info, source_hint=source)
         body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)]
         template = self.from_string(nodes.Template(body, lineno=1))
         return TemplateExpression(template, undefined_to_none)
 
+    def compile_templates(self, target, extensions=None, filter_func=None,
+                          zip='deflated', log_function=None,
+                          ignore_errors=True, py_compile=False):
+        """Finds all the templates the loader can find, compiles them
+        and stores them in `target`.  If `zip` is `None`, instead of in a
+        zipfile, the templates will be will be stored in a directory.
+        By default a deflate zip algorithm is used, to switch to
+        the stored algorithm, `zip` can be set to ``'stored'``.
+
+        `extensions` and `filter_func` are passed to :meth:`list_templates`.
+        Each template returned will be compiled to the target folder or
+        zipfile.
+
+        By default template compilation errors are ignored.  In case a
+        log function is provided, errors are logged.  If you want template
+        syntax errors to abort the compilation you can set `ignore_errors`
+        to `False` and you will get an exception on syntax errors.
+
+        If `py_compile` is set to `True` .pyc files will be written to the
+        target instead of standard .py files.
+
+        .. versionadded:: 2.4
+        """
+        from jinja2.loaders import ModuleLoader
+
+        if log_function is None:
+            log_function = lambda x: None
+
+        if py_compile:
+            import imp, marshal
+            py_header = imp.get_magic() + \
+                u'\xff\xff\xff\xff'.encode('iso-8859-15')
+
+        def write_file(filename, data, mode):
+            if zip:
+                info = ZipInfo(filename)
+                info.external_attr = 0755 << 16L
+                zip_file.writestr(info, data)
+            else:
+                f = open(os.path.join(target, filename), mode)
+                try:
+                    f.write(data)
+                finally:
+                    f.close()
+
+        if zip is not None:
+            from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
+            zip_file = ZipFile(target, 'w', dict(deflated=ZIP_DEFLATED,
+                                                 stored=ZIP_STORED)[zip])
+            log_function('Compiling into Zip archive "%s"' % target)
+        else:
+            if not os.path.isdir(target):
+                os.makedirs(target)
+            log_function('Compiling into folder "%s"' % target)
+
+        try:
+            for name in self.list_templates(extensions, filter_func):
+                source, filename, _ = self.loader.get_source(self, name)
+                try:
+                    code = self.compile(source, name, filename, True, True)
+                except TemplateSyntaxError, e:
+                    if not ignore_errors:
+                        raise
+                    log_function('Could not compile "%s": %s' % (name, e))
+                    continue
+
+                filename = ModuleLoader.get_module_filename(name)
+
+                if py_compile:
+                    c = self._compile(code, _encode_filename(filename))
+                    write_file(filename + 'c', py_header +
+                               marshal.dumps(c), 'wb')
+                    log_function('Byte-compiled "%s" as %s' %
+                                 (name, filename + 'c'))
+                else:
+                    write_file(filename, code, 'w')
+                    log_function('Compiled "%s" as %s' % (name, filename))
+        finally:
+            if zip:
+                zip_file.close()
+
+        log_function('Finished compiling templates')
+
+    def list_templates(self, extensions=None, filter_func=None):
+        """Returns a list of templates for this environment.  This requires
+        that the loader supports the loader's
+        :meth:`~BaseLoader.list_templates` method.
+
+        If there are other files in the template folder besides the
+        actual templates, the returned list can be filtered.  There are two
+        ways: either `extensions` is set to a list of file extensions for
+        templates, or a `filter_func` can be provided which is a callable that
+        is passed a template name and should return `True` if it should end up
+        in the result list.
+
+        If the loader does not support that, a :exc:`TypeError` is raised.
+
+        .. versionadded:: 2.4
+        """
+        x = self.loader.list_templates()
+        if extensions is not None:
+            if filter_func is not None:
+                raise TypeError('either extensions or filter_func '
+                                'can be passed, but not both')
+            filter_func = lambda x: '.' in x and \
+                                    x.rsplit('.', 1)[1] in extensions
+        if filter_func is not None:
+            x = filter(filter_func, x)
+        return x
+
+    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()
+
+        # the debugging module is imported when it's used for the first time.
+        # we're doing a lot of stuff there and for applications that do not
+        # get any exceptions in template rendering there is no need to load
+        # all of that.
+        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`
@@ -473,6 +681,21 @@ class Environment(object):
         """
         return template
 
+    @internalcode
+    def _load_template(self, name, globals):
+        if self.loader is None:
+            raise TypeError('no loader for this environment specified')
+        if self.cache is not None:
+            template = self.cache.get(name)
+            if template is not None and (not self.auto_reload or \
+                                         template.is_up_to_date):
+                return template
+        template = self.loader.load(self, name, globals)
+        if self.cache is not None:
+            self.cache[name] = template
+        return template
+
+    @internalcode
     def get_template(self, name, parent=None, globals=None):
         """Load a template from the loader.  If a loader is configured this
         method ask the loader for the template and returns a :class:`Template`.
@@ -484,22 +707,58 @@ class Environment(object):
 
         If the template does not exist a :exc:`TemplateNotFound` exception is
         raised.
+
+        .. versionchanged:: 2.4
+           If `name` is a :class:`Template` object it is returned from the
+           function unchanged.
         """
-        if self.loader is None:
-            raise TypeError('no loader for this environment specified')
+        if isinstance(name, Template):
+            return name
         if parent is not None:
             name = self.join_path(name, parent)
+        return self._load_template(name, self.make_globals(globals))
 
-        if self.cache is not None:
-            template = self.cache.get(name)
-            if template is not None and (not self.auto_reload or \
-                                         template.is_up_to_date):
-                return template
+    @internalcode
+    def select_template(self, names, parent=None, globals=None):
+        """Works like :meth:`get_template` but tries a number of templates
+        before it fails.  If it cannot find any of the templates, it will
+        raise a :exc:`TemplatesNotFound` exception.
 
-        template = self.loader.load(self, name, self.make_globals(globals))
-        if self.cache is not None:
-            self.cache[name] = template
-        return template
+        .. versionadded:: 2.3
+
+        .. versionchanged:: 2.4
+           If `names` contains a :class:`Template` object it is returned
+           from the function unchanged.
+        """
+        if not names:
+            raise TemplatesNotFound(message=u'Tried to select from an empty list '
+                                            u'of templates.')
+        globals = self.make_globals(globals)
+        for name in names:
+            if isinstance(name, Template):
+                return name
+            if parent is not None:
+                name = self.join_path(name, parent)
+            try:
+                return self._load_template(name, globals)
+            except TemplateNotFound:
+                pass
+        raise TemplatesNotFound(names)
+
+    @internalcode
+    def get_or_select_template(self, template_name_or_list,
+                               parent=None, globals=None):
+        """Does a typecheck and dispatches to :meth:`select_template`
+        if an iterable of template names is given, otherwise to
+        :meth:`get_template`.
+
+        .. versionadded:: 2.3
+        """
+        if isinstance(template_name_or_list, basestring):
+            return self.get_template(template_name_or_list, parent, globals)
+        elif isinstance(template_name_or_list, Template):
+            return template_name_or_list
+        return self.select_template(template_name_or_list, parent, globals)
 
     def from_string(self, source, globals=None, template_class=None):
         """Load a template from a string.  This parses the source given and
@@ -555,6 +814,7 @@ class Template(object):
                 comment_start_string=COMMENT_START_STRING,
                 comment_end_string=COMMENT_END_STRING,
                 line_statement_prefix=LINE_STATEMENT_PREFIX,
+                line_comment_prefix=LINE_COMMENT_PREFIX,
                 trim_blocks=TRIM_BLOCKS,
                 newline_sequence=NEWLINE_SEQUENCE,
                 extensions=(),
@@ -565,9 +825,9 @@ class Template(object):
         env = get_spontaneous_environment(
             block_start_string, block_end_string, variable_start_string,
             variable_end_string, comment_start_string, comment_end_string,
-            line_statement_prefix, trim_blocks, newline_sequence,
-            frozenset(extensions), optimized, undefined, finalize,
-            autoescape, None, 0, False, None)
+            line_statement_prefix, line_comment_prefix, trim_blocks,
+            newline_sequence, frozenset(extensions), optimized, undefined,
+            finalize, autoescape, None, 0, False, None)
         return env.from_string(source, template_class=cls)
 
     @classmethod
@@ -575,16 +835,31 @@ class Template(object):
         """Creates a template object from compiled code and the globals.  This
         is used by the loaders and environment to create a template object.
         """
-        t = object.__new__(cls)
         namespace = {
-            'environment':          environment,
-            '__jinja_template__':   t
+            'environment':  environment,
+            '__file__':     code.co_filename
         }
         exec code in namespace
+        rv = cls._from_namespace(environment, namespace, globals)
+        rv._uptodate = uptodate
+        return rv
+
+    @classmethod
+    def from_module_dict(cls, environment, module_dict, globals):
+        """Creates a template object from a module.  This is used by the
+        module loader to create a template object.
+
+        .. versionadded:: 2.4
+        """
+        return cls._from_namespace(environment, module_dict, globals)
+
+    @classmethod
+    def _from_namespace(cls, environment, namespace, globals):
+        t = object.__new__(cls)
         t.environment = environment
         t.globals = globals
         t.name = namespace['name']
-        t.filename = code.co_filename
+        t.filename = namespace['__file__']
         t.blocks = namespace['blocks']
 
         # render function and module
@@ -593,7 +868,11 @@ class Template(object):
 
         # debug and loader helpers
         t._debug_info = namespace['debug_info']
-        t._uptodate = uptodate
+        t._uptodate = None
+
+        # store the reference
+        namespace['environment'] = environment
+        namespace['__jinja_template__'] = t
 
         return t
 
@@ -610,10 +889,9 @@ class Template(object):
         vars = dict(*args, **kwargs)
         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
+        except Exception:
+            exc_info = sys.exc_info()
+        return self.environment.handle_exception(exc_info, True)
 
     def stream(self, *args, **kwargs):
         """Works exactly like :meth:`generate` but returns a
@@ -633,10 +911,11 @@ class Template(object):
         try:
             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
+        except Exception:
+            exc_info = sys.exc_info()
+        else:
+            return
+        yield self.environment.handle_exception(exc_info, True)
 
     def new_context(self, vars=None, shared=False, locals=None):
         """Create a new :class:`Context` for this template.  The vars
@@ -646,26 +925,13 @@ class Template(object):
 
         `locals` can be a dict of local variables for internal usage.
         """
-        if vars is None:
-            vars = {}
-        if shared:
-            parent = vars
-        else:
-            parent = dict(self.globals, **vars)
-        if locals:
-            # if the parent is shared a copy should be created because
-            # we don't want to modify the dict passed
-            if shared:
-                parent = dict(parent)
-            for key, value in locals.iteritems():
-                if key[:2] == 'l_' and value is not missing:
-                    parent[key[2:]] = value
-        return Context(self.environment, parent, self.name, self.blocks)
+        return new_context(self.environment, self.name, self.blocks,
+                           vars, shared, self.globals, locals)
 
     def make_module(self, vars=None, shared=False, locals=None):
         """This method works like the :attr:`module` attribute when called
-        without arguments but it will evaluate the template every call
-        rather then caching the template.  It's also possible to provide
+        without arguments but it will evaluate the template on every call
+        rather than caching it.  It's also possible to provide
         a dict which is then used as context.  The arguments are the same
         as for the :meth:`new_context` method.
         """
@@ -729,12 +995,19 @@ class TemplateModule(object):
         self.__dict__.update(context.get_exported())
         self.__name__ = template.name
 
-    __unicode__ = lambda x: concat(x._body_stream)
-    __html__ = lambda x: Markup(concat(x._body_stream))
+    def __html__(self):
+        return Markup(concat(self._body_stream))
 
     def __str__(self):
         return unicode(self).encode('utf-8')
 
+    # unicode goes after __str__ because we configured 2to3 to rename
+    # __unicode__ to __str__.  because the 2to3 tree is not designed to
+    # remove nodes from it, we leave the above __str__ around and let
+    # it override at runtime.
+    def __unicode__(self):
+        return concat(self._body_stream)
+
     def __repr__(self):
         if self.__name__ is None:
             name = 'memory:%x' % id(self)