summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArmin Ronacher <armin.ronacher@active-4.com>2008-12-27 13:10:38 +0100
committerArmin Ronacher <armin.ronacher@active-4.com>2008-12-27 13:10:38 +0100
commit37f58cef10de42862fb0d49e1ab7dc47f62af700 (patch)
tree49fb1d8c7826777c020bc6b3d9aff14617ef833b
parent92af75695c273744b63b900330e3222c2d0d1863 (diff)
downloadjinja2-37f58cef10de42862fb0d49e1ab7dc47f62af700.tar.gz
Include statements can now be marked with ``ignore missing`` to skip
non existing templates. --HG-- branch : trunk
-rw-r--r--CHANGES7
-rw-r--r--docs/templates.rst10
-rw-r--r--jinja2/compiler.py27
-rw-r--r--jinja2/nodes.py2
-rw-r--r--jinja2/parser.py6
-rw-r--r--jinja2/runtime.py5
-rw-r--r--tests/test_imports.py11
7 files changed, 58 insertions, 10 deletions
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 %}",