added "with context" or "without context" import/include modifiers

--HG--
branch : trunk
diff --git a/jinja2/compiler.py b/jinja2/compiler.py
index faa8b41..3d4fcbe 100644
--- a/jinja2/compiler.py
+++ b/jinja2/compiler.py
@@ -701,11 +701,17 @@
 
     def visit_Include(self, node, frame):
         """Handles includes."""
-        self.writeline('included_template = environment.get_template(', node)
-        self.visit(node.template, frame)
-        self.write(', %r)' % self.name)
-        self.writeline('for event in included_template.root_render_func('
-                       'included_template.new_context(context.parent, True)):')
+        if node.with_context:
+            self.writeline('template = environment.get_template(', node)
+            self.visit(node.template, frame)
+            self.write(', %r)' % self.name)
+            self.writeline('for event in template.root_render_func('
+                           'template.new_context(context.parent, True)):')
+        else:
+            self.writeline('for event in environment.get_template(', node)
+            self.visit(node.template, frame)
+            self.write(', %r).module._TemplateModule__body_stream:' %
+                       self.name)
         self.indent()
         if frame.buffer is None:
             self.writeline('yield event')
@@ -720,7 +726,11 @@
             self.write('context.vars[%r] = ' % node.target)
         self.write('environment.get_template(')
         self.visit(node.template, frame)
-        self.write(', %r).module' % self.name)
+        self.write(', %r).' % self.name)
+        if node.with_context:
+            self.write('make_module(context.parent, True)')
+        else:
+            self.write('module')
         if frame.toplevel and not node.target.startswith('__'):
             self.writeline('context.exported_vars.discard(%r)' % node.target)
 
@@ -729,7 +739,11 @@
         self.newline(node)
         self.write('included_template = environment.get_template(')
         self.visit(node.template, frame)
-        self.write(', %r).module' % self.name)
+        self.write(', %r).' % self.name)
+        if node.with_context:
+            self.write('make_module(context.parent, True)')
+        else:
+            self.write('module')
         for name in node.names:
             if isinstance(name, tuple):
                 name, alias = name
diff --git a/jinja2/environment.py b/jinja2/environment.py
index ef916a4..68571fd 100644
--- a/jinja2/environment.py
+++ b/jinja2/environment.py
@@ -529,6 +529,12 @@
             parent = dict(self.globals, **vars)
         return Context(self.environment, parent, self.name, self.blocks)
 
+    def make_module(self, vars=None, shared=False):
+        """Like the `module` property but always reevaluates the template
+        and it's possible to provide a context.
+        """
+        return TemplateModule(self, self.new_context(vars, shared))
+
     @property
     def module(self):
         """The template as module.  This is used for imports in the
@@ -543,7 +549,7 @@
         """
         if hasattr(self, '_module'):
             return self._module
-        self._module = rv = TemplateModule(self, self.new_context())
+        self._module = rv = self.make_module()
         return rv
 
     def get_corresponding_lineno(self, lineno):
@@ -583,6 +589,10 @@
     """
 
     def __init__(self, template, context):
+        # don't alter this attribute unless you change it in the
+        # compiler too.  The Include without context passing directly
+        # uses the mangled name.  The reason why we use a mangled one
+        # is to avoid name clashes with macros with those names.
         self.__body_stream = tuple(template.root_render_func(context))
         self.__dict__.update(context.get_exported())
         self.__name__ = template.name
diff --git a/jinja2/lexer.py b/jinja2/lexer.py
index ade9f92..3b65b95 100644
--- a/jinja2/lexer.py
+++ b/jinja2/lexer.py
@@ -218,7 +218,7 @@
         self.current = old_token
         return result
 
-    def skip(self, n):
+    def skip(self, n=1):
         """Got n tokens ahead."""
         for x in xrange(n):
             self.next()
diff --git a/jinja2/nodes.py b/jinja2/nodes.py
index b3255d5..d0372e8 100644
--- a/jinja2/nodes.py
+++ b/jinja2/nodes.py
@@ -265,12 +265,12 @@
 
 class Include(Stmt):
     """A node that represents the include tag."""
-    fields = ('template',)
+    fields = ('template', 'with_context')
 
 
 class Import(Stmt):
     """A node that represents the import tag."""
-    fields = ('template', 'target')
+    fields = ('template', 'target', 'with_context')
 
 
 class FromImport(Stmt):
@@ -284,7 +284,7 @@
 
     The list of names may contain tuples if aliases are wanted.
     """
-    fields = ('template', 'names')
+    fields = ('template', 'names', 'with_context')
 
 
 class Trans(Stmt):
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 84b110c..4239e25 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -123,8 +123,7 @@
         """Parse an if construct."""
         node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
         while 1:
-            # TODO: exclude conditional expressions here
-            node.test = self.parse_tuple()
+            node.test = self.parse_tuple(no_condexpr=True)
             node.body = self.parse_statements(('name:elif', 'name:else',
                                                'name:endif'))
             token = self.stream.next()
@@ -152,10 +151,20 @@
         node.template = self.parse_expression()
         return node
 
+    def parse_import_context(self, node, default):
+        if (self.stream.current.test('name:with') or
+            self.stream.current.test('name:without')) and \
+           self.stream.look().test('name:context'):
+            node.with_context = self.stream.next().value == 'with'
+            self.stream.skip()
+        else:
+            node.with_context = default
+        return node
+
     def parse_include(self):
         node = nodes.Include(lineno=self.stream.next().lineno)
         node.template = self.parse_expression()
-        return node
+        return self.parse_import_context(node, True)
 
     def parse_import(self):
         node = nodes.Import(lineno=self.stream.next().lineno)
@@ -166,17 +175,28 @@
             raise TemplateSyntaxError('can\'t assign imported template '
                                       'to %r' % node.target, node.lineno,
                                       self.filename)
-        return node
+        return self.parse_import_context(node, False)
 
     def parse_from(self):
         node = nodes.FromImport(lineno=self.stream.next().lineno)
         node.template = self.parse_expression()
         self.stream.expect('name:import')
         node.names = []
+
+        def parse_context():
+            if self.stream.current.value in ('with', 'without') and \
+               self.stream.look().test('name:context'):
+                node.with_context = self.stream.next().value == 'with'
+                self.stream.skip()
+                return True
+            return False
+
         while 1:
             if node.names:
                 self.stream.expect('comma')
             if self.stream.current.type is 'name':
+                if parse_context():
+                    break
                 target = nodes.Name(self.stream.current.value, 'store')
                 if not target.can_assign():
                     raise TemplateSyntaxError('can\'t import object named %r'
@@ -198,12 +218,14 @@
                     node.names.append((target.name, alias.value))
                 else:
                     node.names.append(target.name)
-                if self.stream.current.type is not 'comma':
+                if parse_context() or self.stream.current.type is not 'comma':
                     break
             else:
                 break
-        if self.stream.current.type is 'comma':
-            self.stream.next()
+        if not hasattr(node, 'with_context'):
+            node.with_context = False
+            if self.stream.current.type is 'comma':
+                self.stream.next()
         return node
 
     def parse_signature(self, node):