Skip to content

Commit

Permalink
Include statements can now be marked with ignore missing to skip
Browse files Browse the repository at this point in the history
non existing templates.

--HG--
branch : trunk
  • Loading branch information
mitsuhiko committed Dec 27, 2008
1 parent 92af756 commit 37f58ce
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 10 deletions.
7 changes: 7 additions & 0 deletions 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)
Expand Down
10 changes: 10 additions & 0 deletions docs/templates.rst
Expand Up @@ -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
Expand Down
27 changes: 20 additions & 7 deletions jinja2/compiler.py
Expand Up @@ -818,22 +818,35 @@ def visit_Extends(self, node, frame):

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)
Expand Down
2 changes: 1 addition & 1 deletion jinja2/nodes.py
Expand Up @@ -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):
Expand Down
6 changes: 6 additions & 0 deletions jinja2/parser.py
Expand Up @@ -170,6 +170,12 @@ def parse_import_context(self, node, default):
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):
Expand Down
5 changes: 3 additions & 2 deletions jinja2/runtime.py
Expand Up @@ -12,13 +12,14 @@
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
Expand Down
11 changes: 11 additions & 0 deletions tests/test_imports.py
Expand Up @@ -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(
Expand Down Expand Up @@ -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 %}",
Expand Down

0 comments on commit 37f58ce

Please sign in to comment.