From: Armin Ronacher Date: Sat, 27 Dec 2008 12:10:38 +0000 (+0100) Subject: Include statements can now be marked with ``ignore missing`` to skip X-Git-Tag: 2.2~54 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=37f58cef10de42862fb0d49e1ab7dc47f62af700;p=jinja2.git Include statements can now be marked with ``ignore missing`` to skip non existing templates. --HG-- branch : trunk --- diff --git a/CHANGES b/CHANGES index a70061b..ab75555 100644 --- a/CHANGES +++ b/CHANGES @@ -1,6 +1,13 @@ Jinja2 Changelog ================ +Version 2.2 +----------- +(codename unknown, release date yet unknown) + +- Include statements can now be marked with ``ignore missing`` to skip + non existing templates. + Version 2.1.1 ------------- (Bugfix release) diff --git a/docs/templates.rst b/docs/templates.rst index ac80400..fe21eef 100644 --- a/docs/templates.rst +++ b/docs/templates.rst @@ -724,6 +724,16 @@ Included templates have access to the variables of the active context by default. For more details about context behavior of imports and includes see :ref:`import-visibility`. +From Jinja 2.2 onwards you can mark an include with ``ignore missing`` in +which case Jinja will ignore the statement if the template to be ignored +does not exist. When combined with ``with`` or ``without context`` it has +to be placed *before* the context visibility statement. Here some valid +examples:: + + {% include "sidebar.html" ignore missing %} + {% include "sidebar.html" ignore missing with context %} + {% include "sidebar.html" ignore missing without context %} + .. _import: Import diff --git a/jinja2/compiler.py b/jinja2/compiler.py index 54a80ba..e17aa1d 100644 --- a/jinja2/compiler.py +++ b/jinja2/compiler.py @@ -818,22 +818,35 @@ class CodeGenerator(NodeVisitor): def visit_Include(self, node, frame): """Handles includes.""" + if node.ignore_missing: + self.writeline('try:') + self.indent() + self.writeline('template = environment.get_template(', node) + self.visit(node.template, frame) + self.write(', %r)' % self.name) + if node.ignore_missing: + self.outdent() + self.writeline('except TemplateNotFound:') + self.indent() + self.writeline('pass') + self.outdent() + self.writeline('else:') + self.indent() + 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, ' 'locals())):') else: - self.writeline('for event in environment.get_template(', node) - self.visit(node.template, frame) - self.write(', %r).module._body_stream:' % - self.name) + self.writeline('for event in template.module._body_stream:') + self.indent() self.simple_write('event', frame) self.outdent() + if node.ignore_missing: + self.outdent() + def visit_Import(self, node, frame): """Visit regular imports.""" self.writeline('l_%s = ' % node.target, node) diff --git a/jinja2/nodes.py b/jinja2/nodes.py index 405622a..9d78b25 100644 --- a/jinja2/nodes.py +++ b/jinja2/nodes.py @@ -274,7 +274,7 @@ class Block(Stmt): class Include(Stmt): """A node that represents the include tag.""" - fields = ('template', 'with_context') + fields = ('template', 'with_context', 'ignore_missing') class Import(Stmt): diff --git a/jinja2/parser.py b/jinja2/parser.py index d6f1b36..e8f07c5 100644 --- a/jinja2/parser.py +++ b/jinja2/parser.py @@ -170,6 +170,12 @@ class Parser(object): def parse_include(self): node = nodes.Include(lineno=self.stream.next().lineno) node.template = self.parse_expression() + if self.stream.current.test('name:ignore') and \ + self.stream.look().test('name:missing'): + node.ignore_missing = True + self.stream.skip(2) + else: + node.ignore_missing = False return self.parse_import_context(node, True) def parse_import(self): diff --git a/jinja2/runtime.py b/jinja2/runtime.py index 2ed3ac6..87c2354 100644 --- a/jinja2/runtime.py +++ b/jinja2/runtime.py @@ -12,13 +12,14 @@ import sys from itertools import chain, imap from jinja2.utils import Markup, partial, soft_unicode, escape, missing, \ concat, MethodType, FunctionType -from jinja2.exceptions import UndefinedError, TemplateRuntimeError +from jinja2.exceptions import UndefinedError, TemplateRuntimeError, \ + TemplateNotFound # these variables are exported to the template runtime __all__ = ['LoopContext', 'Context', 'TemplateReference', 'Macro', 'Markup', 'TemplateRuntimeError', 'missing', 'concat', 'escape', - 'markup_join', 'unicode_join'] + 'markup_join', 'unicode_join', 'TemplateNotFound'] #: the types we support for context functions diff --git a/tests/test_imports.py b/tests/test_imports.py index bf8f569..224441c 100644 --- a/tests/test_imports.py +++ b/tests/test_imports.py @@ -6,7 +6,9 @@ :copyright: 2007 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ +from py.test import raises from jinja2 import Environment, DictLoader +from jinja2.exceptions import TemplateNotFound test_env = Environment(loader=DictLoader(dict( @@ -40,6 +42,15 @@ def test_context_include(): assert t.render(foo=42) == '[|23]' +def test_include_ignoring_missing(): + t = test_env.from_string('{% include "missing" %}') + raises(TemplateNotFound, t.render) + for extra in '', 'with context', 'without context': + t = test_env.from_string('{% include "missing" ignore missing ' + + extra + ' %}') + assert t.render() == '' + + def test_context_include_with_overrides(): env = Environment(loader=DictLoader(dict( main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",