escape(PyObject *self, PyObject *args)
{
PyObject *text = NULL, *s = NULL, *rv = NULL;
- if (!PyArg_UnpackTuple(args, "escape", 1, 2, &text))
+ if (!PyArg_UnpackTuple(args, "escape", 1, 1, &text))
return NULL;
/* we don't have to escape integers, bools or floats */
"""Represents a template."""
def __init__(self, environment, code, globals, uptodate=None):
- namespace = {'environment': environment}
+ namespace = {
+ 'environment': environment,
+ '__jinja_template__': self
+ }
exec code in namespace
self.environment = environment
self.name = namespace['name']
self.blocks = namespace['blocks']
self.globals = globals
- # debug helpers
+ # debug and loader helpers
self._get_debug_info = namespace['get_debug_info']
self._uptodate = uptodate
- namespace['__jinja_template__'] = self
def render(self, *args, **kwargs):
"""Render the template into a string."""
- return u''.join(self.generate(*args, **kwargs))
+ try:
+ return u''.join(self.generate(*args, **kwargs))
+ except:
+ # hide the `generate` frame
+ exc_type, exc_value, tb = sys.exc_info()
+ raise exc_type, exc_value, tb.tb_next
def stream(self, *args, **kwargs):
"""Return a `TemplateStream` that generates the template."""
- return TemplateStream(self.generate(*args, **kwargs))
+ try:
+ return TemplateStream(self.generate(*args, **kwargs))
+ except:
+ # hide the `generate` frame
+ exc_type, exc_value, tb = sys.exc_info()
+ raise exc_type, exc_value, tb.tb_next
def generate(self, *args, **kwargs):
"""Return a generator that generates the template."""
"""
def __init__(self, cache_size=50, auto_reload=True):
- if cache_size > 0:
- self.cache = LRUCache(cache_size)
- else:
+ if cache_size == 0:
self.cache = None
+ elif cache_size < 0:
+ self.cache = {}
+ else:
+ self.cache = LRUCache(cache_size)
self.auto_reload = auto_reload
def get_source(self, environment, template):
class DictLoader(BaseLoader):
"""Loads a template from a python dict. Used for unittests mostly."""
- def __init__(self, mapping):
+ def __init__(self, mapping, cache_size=50):
+ BaseLoader.__init__(self, cache_size, False)
self.mapping = mapping
def get_source(self, environment, template):
self._undefined_name
)
else:
- hint = '%r object has no attribute %s' % (
+ hint = '%r object has no attribute %r' % (
self._undefined_obj.__class__.__name__,
self._undefined_name
)
import py
from jinja2 import Environment
-from jinja2.parser import Parser
+from jinja2.loaders import BaseLoader
+from jinja2.exceptions import TemplateNotFound
try:
# This code adds support for coverage.py (see
coverage = None
-class GlobalLoader(object):
+class GlobalLoader(BaseLoader):
+ scope = globals()
- def __init__(self, scope):
- self.scope = scope
+ def get_source(self, environment, name):
+ try:
+ return self.scope[name.upper() + 'TEMPLATE'], None, None
+ except KeyError:
+ raise TemplateNotFound(name)
- def get_source(self, environment, name, parent, scope=None):
- return self.scope[name.upper() + 'TEMPLATE']
- def parse(self, environment, name, parent, scope=None):
- return Parser(environment, self.get_source(environment, name,
- parent, scope), name).parse()
-
- def load(self, environment, name, translator, scope=None):
- return translator.process(environment, self.parse(environment,
- name, None, scope))
-
-
-loader = GlobalLoader(globals())
+loader = GlobalLoader(cache_size=0)
simple_env = Environment(trim_blocks=True, loader=loader)
-class MemcacheClient(object):
- """
- Helper for the loader test.
- """
-
- def __init__(self, hosts):
- self.cache = {}
-
- def get(self, name):
- return self.cache.get(name)
-
- def set(self, name, data, time):
- self.cache[name] = data
-
-sys.modules['memcache'] = memcache = type(sys)('memcache')
-memcache.Client = MemcacheClient
-
-
class Module(py.test.collect.Module):
def __init__(self, *args, **kwargs):
{% block block3 %}block 3 from level4{% endblock %}
'''
-BROKENTEMPLATE = '''\
-{% extends "layout" %}
-{% if false %}
- {% block block1 %}
- this is broken
- {% endblock %}
-{% endif %}
-'''
-
WORKINGTEMPLATE = '''\
{% extends "layout" %}
{% block block1 %}
assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER'
-def test_broken(env):
- try:
- tmpl = env.get_template('broken')
- except TemplateSyntaxError:
- pass
- else:
- raise RuntimeError('no syntax error occured')
-
-
def test_working(env):
tmpl = env.get_template('working')
-
-
-def test_shortcut(env):
- tmpl = env.from_string('{% block foo "42" %}')
- assert tmpl.render() == '42'
# -*- coding: utf-8 -*-
"""
- unit test for the undefined singletons
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ unit test for the undefined types
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- :copyright: 2007 by Armin Ronacher.
+ :copyright: 2008 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
-from jinja2 import Environment
-from jinja2.exceptions import TemplateRuntimeError
-from jinja2.datastructure import SilentUndefined, ComplainingUndefined
-
-silent_env = Environment(undefined_singleton=SilentUndefined)
-complaining_env = Environment(undefined_singleton=ComplainingUndefined)
-
-
-JUSTUNDEFINED = '''{{ missing }}'''
-DEFINEDUNDEFINED = '''{{ missing is defined }}|{{ given is defined }}'''
-ITERATION = '''{% for item in missing %}{{ item }}{% endfor %}'''
-CONCATENATION = '''{{ missing + [1, 2] + missing + [3] }}'''
-
-
-def test_silent_defined():
- tmpl = silent_env.from_string(DEFINEDUNDEFINED)
- assert tmpl.render(given=0) == 'False|True'
-
-
-def test_complaining_defined():
- tmpl = complaining_env.from_string(DEFINEDUNDEFINED)
- assert tmpl.render(given=0) == 'False|True'
-
-
-def test_silent_rendering():
- tmpl = silent_env.from_string(JUSTUNDEFINED)
- assert tmpl.render() == ''
-
-
-def test_complaining_undefined():
- tmpl = complaining_env.from_string(JUSTUNDEFINED)
- try:
- tmpl.render()
- except TemplateRuntimeError:
- pass
- else:
- raise ValueError('template runtime error expected')
-
-
-def test_silent_iteration():
- tmpl = silent_env.from_string(ITERATION)
- assert tmpl.render() == ''
-
-
-def test_complaining_iteration():
- tmpl = complaining_env.from_string(ITERATION)
- try:
- tmpl.render()
- except TemplateRuntimeError:
- pass
- else:
- raise ValueError('template runtime error expected')
-
-
-def test_concatenation():
- tmpl = silent_env.from_string(CONCATENATION)
- assert tmpl.render() == '[1, 2, 3]'
+test_default_undefined = '''
+>>> from jinja2 import Environment, Undefined
+>>> env = Environment(undefined=Undefined)
+>>> env.from_string('{{ missing }}').render()
+u''
+>>> env.from_string('{{ missing.attribute }}').render()
+Traceback (most recent call last):
+ ...
+UndefinedError: 'missing' is undefined
+>>> env.from_string('{{ missing|list }}').render()
+u'[]'
+>>> env.from_string('{{ missing is not defined }}').render()
+u'True'
+>>> env.from_string('{{ foo.missing }}').render(foo=42)
+u''
+>>> env.from_string('{{ not missing }}').render()
+u'True'
+'''
+
+test_debug_undefined = '''
+>>> from jinja2 import Environment, DebugUndefined
+>>> env = Environment(undefined=DebugUndefined)
+>>> env.from_string('{{ missing }}').render()
+u'{{ missing }}'
+>>> env.from_string('{{ missing.attribute }}').render()
+Traceback (most recent call last):
+ ...
+UndefinedError: 'missing' is undefined
+>>> env.from_string('{{ missing|list }}').render()
+u'[]'
+>>> env.from_string('{{ missing is not defined }}').render()
+u'True'
+>>> env.from_string('{{ foo.missing }}').render(foo=42)
+u"{{ no such element: int['missing'] }}"
+>>> env.from_string('{{ not missing }}').render()
+u'True'
+'''
+
+test_strict_undefined = '''
+>>> from jinja2 import Environment, StrictUndefined
+>>> env = Environment(undefined=StrictUndefined)
+>>> env.from_string('{{ missing }}').render()
+Traceback (most recent call last):
+ ...
+UndefinedError: 'missing' is undefined
+>>> env.from_string('{{ missing.attribute }}').render()
+Traceback (most recent call last):
+ ...
+UndefinedError: 'missing' is undefined
+>>> env.from_string('{{ missing|list }}').render()
+Traceback (most recent call last):
+ ...
+UndefinedError: 'missing' is undefined
+>>> env.from_string('{{ missing is not defined }}').render()
+u'True'
+>>> env.from_string('{{ foo.missing }}').render(foo=42)
+Traceback (most recent call last):
+ ...
+UndefinedError: 'int' object has no attribute 'missing'
+>>> env.from_string('{{ not missing }}').render()
+Traceback (most recent call last):
+ ...
+UndefinedError: 'missing' is undefined
+'''