mirror of
https://github.com/opencv/opencv.git
synced 2024-11-29 05:29:54 +08:00
Template population now functional
This commit is contained in:
parent
827b4f93e4
commit
66c40bee6f
@ -1,6 +1,6 @@
|
||||
#/usr/bin/env python
|
||||
|
||||
import sys, re, os.path
|
||||
import sys, re, os, time
|
||||
from string import Template
|
||||
from hdr_parser import CppHeaderParser
|
||||
from parse_tree import ParseTree, todict
|
||||
@ -9,7 +9,7 @@ from jinja2 import Environment, PackageLoader
|
||||
|
||||
class MatlabWrapperGenerator(object):
|
||||
|
||||
def gen(self, input_files, output_files):
|
||||
def gen(self, input_files, output_dir):
|
||||
# parse each of the files and store in a dictionary
|
||||
# as a separate "namespace"
|
||||
parser = CppHeaderParser()
|
||||
@ -24,7 +24,7 @@ class MatlabWrapperGenerator(object):
|
||||
parse_tree.build(ns)
|
||||
|
||||
# setup the template engine
|
||||
jtemplate = Environment(loader=PackageLoader('templates', ''))
|
||||
jtemplate = Environment(loader=PackageLoader('templates', ''), trim_blocks=True)
|
||||
|
||||
# add the custom filters
|
||||
jtemplate.filters['toUpperCamelCase'] = toUpperCamelCase
|
||||
@ -33,9 +33,23 @@ class MatlabWrapperGenerator(object):
|
||||
jtemplate.filters['comment'] = comment
|
||||
|
||||
# load the templates
|
||||
function = jtemplate.get_template('template_function_base.cpp')
|
||||
classm = jtemplate.get_template('template_class_base.m')
|
||||
classc = jtemplate.get_template('template_class_base.cpp')
|
||||
doc = jtemplate.get_template('template_doc_base.m')
|
||||
tfunction = jtemplate.get_template('template_function_base.cpp')
|
||||
tclassm = jtemplate.get_template('template_class_base.m')
|
||||
tclassc = jtemplate.get_template('template_class_base.cpp')
|
||||
tdoc = jtemplate.get_template('template_doc_base.m')
|
||||
|
||||
# create the build directory
|
||||
if not os.path.isdir(output_dir):
|
||||
os.mkdir(output_dir)
|
||||
|
||||
# populate!
|
||||
function = parse_tree.namespaces[0].functions[0]
|
||||
print function
|
||||
populated = tfunction.render(fun=function, time=time)
|
||||
with open(output_dir+'/'+function.name+'.cpp', 'wb') as f:
|
||||
f.write(populated)
|
||||
#for name, namespace in ns:
|
||||
# for function in namespace.functions:
|
||||
# print 'populating function tempaltes from '+name
|
||||
# populated = tfunction.render(function)
|
||||
|
||||
|
31
modules/matlab/generator/jinja2/AUTHORS
Normal file
31
modules/matlab/generator/jinja2/AUTHORS
Normal file
@ -0,0 +1,31 @@
|
||||
Jinja is written and maintained by the Jinja Team and various
|
||||
contributors:
|
||||
|
||||
Lead Developer:
|
||||
|
||||
- Armin Ronacher <armin.ronacher@active-4.com>
|
||||
|
||||
Developers:
|
||||
|
||||
- Christoph Hack
|
||||
- Georg Brandl
|
||||
|
||||
Contributors:
|
||||
|
||||
- Bryan McLemore
|
||||
- Mickaël Guérin <kael@crocobox.org>
|
||||
- Cameron Knight
|
||||
- Lawrence Journal-World.
|
||||
- David Cramer
|
||||
|
||||
Patches and suggestions:
|
||||
|
||||
- Ronny Pfannschmidt
|
||||
- Axel Böhm
|
||||
- Alexey Melchakov
|
||||
- Bryan McLemore
|
||||
- Clovis Fabricio (nosklo)
|
||||
- Cameron Knight
|
||||
- Peter van Dijk (Habbie)
|
||||
- Stefan Ebner
|
||||
- Rene Leonhardt
|
31
modules/matlab/generator/jinja2/LICENSE
Normal file
31
modules/matlab/generator/jinja2/LICENSE
Normal file
@ -0,0 +1,31 @@
|
||||
Copyright (c) 2009 by the Jinja Team, see AUTHORS for more details.
|
||||
|
||||
Some rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials provided
|
||||
with the distribution.
|
||||
|
||||
* The names of the contributors may not be used to endorse or
|
||||
promote products derived from this software without specific
|
||||
prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
@ -1,161 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.tests
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Jinja test functions. Used with the "is" operator.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import re
|
||||
from jinja2.runtime import Undefined
|
||||
|
||||
try:
|
||||
from collections import Mapping as MappingType
|
||||
except ImportError:
|
||||
import UserDict
|
||||
MappingType = (UserDict.UserDict, UserDict.DictMixin, dict)
|
||||
|
||||
# nose, nothing here to test
|
||||
__test__ = False
|
||||
|
||||
|
||||
number_re = re.compile(r'^-?\d+(\.\d+)?$')
|
||||
regex_type = type(number_re)
|
||||
|
||||
|
||||
try:
|
||||
test_callable = callable
|
||||
except NameError:
|
||||
def test_callable(x):
|
||||
return hasattr(x, '__call__')
|
||||
|
||||
|
||||
def test_odd(value):
|
||||
"""Return true if the variable is odd."""
|
||||
return value % 2 == 1
|
||||
|
||||
|
||||
def test_even(value):
|
||||
"""Return true if the variable is even."""
|
||||
return value % 2 == 0
|
||||
|
||||
|
||||
def test_divisibleby(value, num):
|
||||
"""Check if a variable is divisible by a number."""
|
||||
return value % num == 0
|
||||
|
||||
|
||||
def test_defined(value):
|
||||
"""Return true if the variable is defined:
|
||||
|
||||
.. sourcecode:: jinja
|
||||
|
||||
{% if variable is defined %}
|
||||
value of variable: {{ variable }}
|
||||
{% else %}
|
||||
variable is not defined
|
||||
{% endif %}
|
||||
|
||||
See the :func:`default` filter for a simple way to set undefined
|
||||
variables.
|
||||
"""
|
||||
return not isinstance(value, Undefined)
|
||||
|
||||
|
||||
def test_undefined(value):
|
||||
"""Like :func:`defined` but the other way round."""
|
||||
return isinstance(value, Undefined)
|
||||
|
||||
|
||||
def test_none(value):
|
||||
"""Return true if the variable is none."""
|
||||
return value is None
|
||||
|
||||
|
||||
def test_lower(value):
|
||||
"""Return true if the variable is lowercased."""
|
||||
return unicode(value).islower()
|
||||
|
||||
|
||||
def test_upper(value):
|
||||
"""Return true if the variable is uppercased."""
|
||||
return unicode(value).isupper()
|
||||
|
||||
|
||||
def test_string(value):
|
||||
"""Return true if the object is a string."""
|
||||
return isinstance(value, basestring)
|
||||
|
||||
|
||||
def test_mapping(value):
|
||||
"""Return true if the object is a mapping (dict etc.).
|
||||
|
||||
.. versionadded:: 2.6
|
||||
"""
|
||||
return isinstance(value, MappingType)
|
||||
|
||||
|
||||
def test_number(value):
|
||||
"""Return true if the variable is a number."""
|
||||
return isinstance(value, (int, long, float, complex))
|
||||
|
||||
|
||||
def test_sequence(value):
|
||||
"""Return true if the variable is a sequence. Sequences are variables
|
||||
that are iterable.
|
||||
"""
|
||||
try:
|
||||
len(value)
|
||||
value.__getitem__
|
||||
except:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def test_sameas(value, other):
|
||||
"""Check if an object points to the same memory address than another
|
||||
object:
|
||||
|
||||
.. sourcecode:: jinja
|
||||
|
||||
{% if foo.attribute is sameas false %}
|
||||
the foo attribute really is the `False` singleton
|
||||
{% endif %}
|
||||
"""
|
||||
return value is other
|
||||
|
||||
|
||||
def test_iterable(value):
|
||||
"""Check if it's possible to iterate over an object."""
|
||||
try:
|
||||
iter(value)
|
||||
except TypeError:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def test_escaped(value):
|
||||
"""Check if the value is escaped."""
|
||||
return hasattr(value, '__html__')
|
||||
|
||||
|
||||
TESTS = {
|
||||
'odd': test_odd,
|
||||
'even': test_even,
|
||||
'divisibleby': test_divisibleby,
|
||||
'defined': test_defined,
|
||||
'undefined': test_undefined,
|
||||
'none': test_none,
|
||||
'lower': test_lower,
|
||||
'upper': test_upper,
|
||||
'string': test_string,
|
||||
'mapping': test_mapping,
|
||||
'number': test_number,
|
||||
'sequence': test_sequence,
|
||||
'iterable': test_iterable,
|
||||
'callable': test_callable,
|
||||
'sameas': test_sameas,
|
||||
'escaped': test_escaped
|
||||
}
|
@ -1,95 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
All the unittests of Jinja2. These tests can be executed by
|
||||
either running run-tests.py using multiple Python versions at
|
||||
the same time.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import unittest
|
||||
from traceback import format_exception
|
||||
from jinja2 import loaders
|
||||
|
||||
|
||||
here = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
dict_loader = loaders.DictLoader({
|
||||
'justdict.html': 'FOO'
|
||||
})
|
||||
package_loader = loaders.PackageLoader('jinja2.testsuite.res', 'templates')
|
||||
filesystem_loader = loaders.FileSystemLoader(here + '/res/templates')
|
||||
function_loader = loaders.FunctionLoader({'justfunction.html': 'FOO'}.get)
|
||||
choice_loader = loaders.ChoiceLoader([dict_loader, package_loader])
|
||||
prefix_loader = loaders.PrefixLoader({
|
||||
'a': filesystem_loader,
|
||||
'b': dict_loader
|
||||
})
|
||||
|
||||
|
||||
class JinjaTestCase(unittest.TestCase):
|
||||
|
||||
### use only these methods for testing. If you need standard
|
||||
### unittest method, wrap them!
|
||||
|
||||
def setup(self):
|
||||
pass
|
||||
|
||||
def teardown(self):
|
||||
pass
|
||||
|
||||
def setUp(self):
|
||||
self.setup()
|
||||
|
||||
def tearDown(self):
|
||||
self.teardown()
|
||||
|
||||
def assert_equal(self, a, b):
|
||||
return self.assertEqual(a, b)
|
||||
|
||||
def assert_raises(self, *args, **kwargs):
|
||||
return self.assertRaises(*args, **kwargs)
|
||||
|
||||
def assert_traceback_matches(self, callback, expected_tb):
|
||||
try:
|
||||
callback()
|
||||
except Exception, e:
|
||||
tb = format_exception(*sys.exc_info())
|
||||
if re.search(expected_tb.strip(), ''.join(tb)) is None:
|
||||
raise self.fail('Traceback did not match:\n\n%s\nexpected:\n%s'
|
||||
% (''.join(tb), expected_tb))
|
||||
else:
|
||||
self.fail('Expected exception')
|
||||
|
||||
|
||||
def suite():
|
||||
from jinja2.testsuite import ext, filters, tests, core_tags, \
|
||||
loader, inheritance, imports, lexnparse, security, api, \
|
||||
regression, debug, utils, doctests
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(ext.suite())
|
||||
suite.addTest(filters.suite())
|
||||
suite.addTest(tests.suite())
|
||||
suite.addTest(core_tags.suite())
|
||||
suite.addTest(loader.suite())
|
||||
suite.addTest(inheritance.suite())
|
||||
suite.addTest(imports.suite())
|
||||
suite.addTest(lexnparse.suite())
|
||||
suite.addTest(security.suite())
|
||||
suite.addTest(api.suite())
|
||||
suite.addTest(regression.suite())
|
||||
suite.addTest(debug.suite())
|
||||
suite.addTest(utils.suite())
|
||||
|
||||
# doctests will not run on python 3 currently. Too many issues
|
||||
# with that, do not test that on that platform.
|
||||
if sys.version_info < (3, 0):
|
||||
suite.addTest(doctests.suite())
|
||||
|
||||
return suite
|
@ -1,245 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.api
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the public API and related stuff.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment, Undefined, DebugUndefined, \
|
||||
StrictUndefined, UndefinedError, meta, \
|
||||
is_undefined, Template, DictLoader
|
||||
from jinja2.utils import Cycler
|
||||
|
||||
env = Environment()
|
||||
|
||||
|
||||
class ExtendedAPITestCase(JinjaTestCase):
|
||||
|
||||
def test_item_and_attribute(self):
|
||||
from jinja2.sandbox import SandboxedEnvironment
|
||||
|
||||
for env in Environment(), SandboxedEnvironment():
|
||||
# the |list is necessary for python3
|
||||
tmpl = env.from_string('{{ foo.items()|list }}')
|
||||
assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
|
||||
tmpl = env.from_string('{{ foo|attr("items")()|list }}')
|
||||
assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
|
||||
tmpl = env.from_string('{{ foo["items"] }}')
|
||||
assert tmpl.render(foo={'items': 42}) == '42'
|
||||
|
||||
def test_finalizer(self):
|
||||
def finalize_none_empty(value):
|
||||
if value is None:
|
||||
value = u''
|
||||
return value
|
||||
env = Environment(finalize=finalize_none_empty)
|
||||
tmpl = env.from_string('{% for item in seq %}|{{ item }}{% endfor %}')
|
||||
assert tmpl.render(seq=(None, 1, "foo")) == '||1|foo'
|
||||
tmpl = env.from_string('<{{ none }}>')
|
||||
assert tmpl.render() == '<>'
|
||||
|
||||
def test_cycler(self):
|
||||
items = 1, 2, 3
|
||||
c = Cycler(*items)
|
||||
for item in items + items:
|
||||
assert c.current == item
|
||||
assert c.next() == item
|
||||
c.next()
|
||||
assert c.current == 2
|
||||
c.reset()
|
||||
assert c.current == 1
|
||||
|
||||
def test_expressions(self):
|
||||
expr = env.compile_expression("foo")
|
||||
assert expr() is None
|
||||
assert expr(foo=42) == 42
|
||||
expr2 = env.compile_expression("foo", undefined_to_none=False)
|
||||
assert is_undefined(expr2())
|
||||
|
||||
expr = env.compile_expression("42 + foo")
|
||||
assert expr(foo=42) == 84
|
||||
|
||||
def test_template_passthrough(self):
|
||||
t = Template('Content')
|
||||
assert env.get_template(t) is t
|
||||
assert env.select_template([t]) is t
|
||||
assert env.get_or_select_template([t]) is t
|
||||
assert env.get_or_select_template(t) is t
|
||||
|
||||
def test_autoescape_autoselect(self):
|
||||
def select_autoescape(name):
|
||||
if name is None or '.' not in name:
|
||||
return False
|
||||
return name.endswith('.html')
|
||||
env = Environment(autoescape=select_autoescape,
|
||||
loader=DictLoader({
|
||||
'test.txt': '{{ foo }}',
|
||||
'test.html': '{{ foo }}'
|
||||
}))
|
||||
t = env.get_template('test.txt')
|
||||
assert t.render(foo='<foo>') == '<foo>'
|
||||
t = env.get_template('test.html')
|
||||
assert t.render(foo='<foo>') == '<foo>'
|
||||
t = env.from_string('{{ foo }}')
|
||||
assert t.render(foo='<foo>') == '<foo>'
|
||||
|
||||
|
||||
class MetaTestCase(JinjaTestCase):
|
||||
|
||||
def test_find_undeclared_variables(self):
|
||||
ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
|
||||
x = meta.find_undeclared_variables(ast)
|
||||
assert x == set(['bar'])
|
||||
|
||||
ast = env.parse('{% set foo = 42 %}{{ bar + foo }}'
|
||||
'{% macro meh(x) %}{{ x }}{% endmacro %}'
|
||||
'{% for item in seq %}{{ muh(item) + meh(seq) }}{% endfor %}')
|
||||
x = meta.find_undeclared_variables(ast)
|
||||
assert x == set(['bar', 'seq', 'muh'])
|
||||
|
||||
def test_find_refererenced_templates(self):
|
||||
ast = env.parse('{% extends "layout.html" %}{% include helper %}')
|
||||
i = meta.find_referenced_templates(ast)
|
||||
assert i.next() == 'layout.html'
|
||||
assert i.next() is None
|
||||
assert list(i) == []
|
||||
|
||||
ast = env.parse('{% extends "layout.html" %}'
|
||||
'{% from "test.html" import a, b as c %}'
|
||||
'{% import "meh.html" as meh %}'
|
||||
'{% include "muh.html" %}')
|
||||
i = meta.find_referenced_templates(ast)
|
||||
assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html']
|
||||
|
||||
def test_find_included_templates(self):
|
||||
ast = env.parse('{% include ["foo.html", "bar.html"] %}')
|
||||
i = meta.find_referenced_templates(ast)
|
||||
assert list(i) == ['foo.html', 'bar.html']
|
||||
|
||||
ast = env.parse('{% include ("foo.html", "bar.html") %}')
|
||||
i = meta.find_referenced_templates(ast)
|
||||
assert list(i) == ['foo.html', 'bar.html']
|
||||
|
||||
ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
|
||||
i = meta.find_referenced_templates(ast)
|
||||
assert list(i) == ['foo.html', 'bar.html', None]
|
||||
|
||||
ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
|
||||
i = meta.find_referenced_templates(ast)
|
||||
assert list(i) == ['foo.html', 'bar.html', None]
|
||||
|
||||
|
||||
class StreamingTestCase(JinjaTestCase):
|
||||
|
||||
def test_basic_streaming(self):
|
||||
tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index "
|
||||
"}} - {{ item }}</li>{%- endfor %}</ul>")
|
||||
stream = tmpl.stream(seq=range(4))
|
||||
self.assert_equal(stream.next(), '<ul>')
|
||||
self.assert_equal(stream.next(), '<li>1 - 0</li>')
|
||||
self.assert_equal(stream.next(), '<li>2 - 1</li>')
|
||||
self.assert_equal(stream.next(), '<li>3 - 2</li>')
|
||||
self.assert_equal(stream.next(), '<li>4 - 3</li>')
|
||||
self.assert_equal(stream.next(), '</ul>')
|
||||
|
||||
def test_buffered_streaming(self):
|
||||
tmpl = env.from_string("<ul>{% for item in seq %}<li>{{ loop.index "
|
||||
"}} - {{ item }}</li>{%- endfor %}</ul>")
|
||||
stream = tmpl.stream(seq=range(4))
|
||||
stream.enable_buffering(size=3)
|
||||
self.assert_equal(stream.next(), u'<ul><li>1 - 0</li><li>2 - 1</li>')
|
||||
self.assert_equal(stream.next(), u'<li>3 - 2</li><li>4 - 3</li></ul>')
|
||||
|
||||
def test_streaming_behavior(self):
|
||||
tmpl = env.from_string("")
|
||||
stream = tmpl.stream()
|
||||
assert not stream.buffered
|
||||
stream.enable_buffering(20)
|
||||
assert stream.buffered
|
||||
stream.disable_buffering()
|
||||
assert not stream.buffered
|
||||
|
||||
|
||||
class UndefinedTestCase(JinjaTestCase):
|
||||
|
||||
def test_stopiteration_is_undefined(self):
|
||||
def test():
|
||||
raise StopIteration()
|
||||
t = Template('A{{ test() }}B')
|
||||
assert t.render(test=test) == 'AB'
|
||||
t = Template('A{{ test().missingattribute }}B')
|
||||
self.assert_raises(UndefinedError, t.render, test=test)
|
||||
|
||||
def test_undefined_and_special_attributes(self):
|
||||
try:
|
||||
Undefined('Foo').__dict__
|
||||
except AttributeError:
|
||||
pass
|
||||
else:
|
||||
assert False, "Expected actual attribute error"
|
||||
|
||||
def test_default_undefined(self):
|
||||
env = Environment(undefined=Undefined)
|
||||
self.assert_equal(env.from_string('{{ missing }}').render(), u'')
|
||||
self.assert_raises(UndefinedError,
|
||||
env.from_string('{{ missing.attribute }}').render)
|
||||
self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
|
||||
self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
|
||||
self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42), '')
|
||||
self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
|
||||
|
||||
def test_debug_undefined(self):
|
||||
env = Environment(undefined=DebugUndefined)
|
||||
self.assert_equal(env.from_string('{{ missing }}').render(), '{{ missing }}')
|
||||
self.assert_raises(UndefinedError,
|
||||
env.from_string('{{ missing.attribute }}').render)
|
||||
self.assert_equal(env.from_string('{{ missing|list }}').render(), '[]')
|
||||
self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
|
||||
self.assert_equal(env.from_string('{{ foo.missing }}').render(foo=42),
|
||||
u"{{ no such element: int object['missing'] }}")
|
||||
self.assert_equal(env.from_string('{{ not missing }}').render(), 'True')
|
||||
|
||||
def test_strict_undefined(self):
|
||||
env = Environment(undefined=StrictUndefined)
|
||||
self.assert_raises(UndefinedError, env.from_string('{{ missing }}').render)
|
||||
self.assert_raises(UndefinedError, env.from_string('{{ missing.attribute }}').render)
|
||||
self.assert_raises(UndefinedError, env.from_string('{{ missing|list }}').render)
|
||||
self.assert_equal(env.from_string('{{ missing is not defined }}').render(), 'True')
|
||||
self.assert_raises(UndefinedError, env.from_string('{{ foo.missing }}').render, foo=42)
|
||||
self.assert_raises(UndefinedError, env.from_string('{{ not missing }}').render)
|
||||
|
||||
def test_indexing_gives_undefined(self):
|
||||
t = Template("{{ var[42].foo }}")
|
||||
self.assert_raises(UndefinedError, t.render, var=0)
|
||||
|
||||
def test_none_gives_proper_error(self):
|
||||
try:
|
||||
Environment().getattr(None, 'split')()
|
||||
except UndefinedError, e:
|
||||
assert e.message == "'None' has no attribute 'split'"
|
||||
else:
|
||||
assert False, 'expected exception'
|
||||
|
||||
def test_object_repr(self):
|
||||
try:
|
||||
Undefined(obj=42, name='upper')()
|
||||
except UndefinedError, e:
|
||||
assert e.message == "'int object' has no attribute 'upper'"
|
||||
else:
|
||||
assert False, 'expected exception'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ExtendedAPITestCase))
|
||||
suite.addTest(unittest.makeSuite(MetaTestCase))
|
||||
suite.addTest(unittest.makeSuite(StreamingTestCase))
|
||||
suite.addTest(unittest.makeSuite(UndefinedTestCase))
|
||||
return suite
|
@ -1,285 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.core_tags
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Test the core tags like for and if.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment, TemplateSyntaxError, UndefinedError, \
|
||||
DictLoader
|
||||
|
||||
env = Environment()
|
||||
|
||||
|
||||
class ForLoopTestCase(JinjaTestCase):
|
||||
|
||||
def test_simple(self):
|
||||
tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}')
|
||||
assert tmpl.render(seq=range(10)) == '0123456789'
|
||||
|
||||
def test_else(self):
|
||||
tmpl = env.from_string('{% for item in seq %}XXX{% else %}...{% endfor %}')
|
||||
assert tmpl.render() == '...'
|
||||
|
||||
def test_empty_blocks(self):
|
||||
tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>')
|
||||
assert tmpl.render() == '<>'
|
||||
|
||||
def test_context_vars(self):
|
||||
tmpl = env.from_string('''{% for item in seq -%}
|
||||
{{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
|
||||
loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
|
||||
loop.length }}###{% endfor %}''')
|
||||
one, two, _ = tmpl.render(seq=[0, 1]).split('###')
|
||||
(one_index, one_index0, one_revindex, one_revindex0, one_first,
|
||||
one_last, one_length) = one.split('|')
|
||||
(two_index, two_index0, two_revindex, two_revindex0, two_first,
|
||||
two_last, two_length) = two.split('|')
|
||||
|
||||
assert int(one_index) == 1 and int(two_index) == 2
|
||||
assert int(one_index0) == 0 and int(two_index0) == 1
|
||||
assert int(one_revindex) == 2 and int(two_revindex) == 1
|
||||
assert int(one_revindex0) == 1 and int(two_revindex0) == 0
|
||||
assert one_first == 'True' and two_first == 'False'
|
||||
assert one_last == 'False' and two_last == 'True'
|
||||
assert one_length == two_length == '2'
|
||||
|
||||
def test_cycling(self):
|
||||
tmpl = env.from_string('''{% for item in seq %}{{
|
||||
loop.cycle('<1>', '<2>') }}{% endfor %}{%
|
||||
for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''')
|
||||
output = tmpl.render(seq=range(4), through=('<1>', '<2>'))
|
||||
assert output == '<1><2>' * 4
|
||||
|
||||
def test_scope(self):
|
||||
tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}')
|
||||
output = tmpl.render(seq=range(10))
|
||||
assert not output
|
||||
|
||||
def test_varlen(self):
|
||||
def inner():
|
||||
for item in range(5):
|
||||
yield item
|
||||
tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}')
|
||||
output = tmpl.render(iter=inner())
|
||||
assert output == '01234'
|
||||
|
||||
def test_noniter(self):
|
||||
tmpl = env.from_string('{% for item in none %}...{% endfor %}')
|
||||
self.assert_raises(TypeError, tmpl.render)
|
||||
|
||||
def test_recursive(self):
|
||||
tmpl = env.from_string('''{% for item in seq recursive -%}
|
||||
[{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render(seq=[
|
||||
dict(a=1, b=[dict(a=1), dict(a=2)]),
|
||||
dict(a=2, b=[dict(a=1), dict(a=2)]),
|
||||
dict(a=3, b=[dict(a='a')])
|
||||
]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
|
||||
|
||||
def test_looploop(self):
|
||||
tmpl = env.from_string('''{% for row in table %}
|
||||
{%- set rowloop = loop -%}
|
||||
{% for cell in row -%}
|
||||
[{{ rowloop.index }}|{{ loop.index }}]
|
||||
{%- endfor %}
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
|
||||
|
||||
def test_reversed_bug(self):
|
||||
tmpl = env.from_string('{% for i in items %}{{ i }}'
|
||||
'{% if not loop.last %}'
|
||||
',{% endif %}{% endfor %}')
|
||||
assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
|
||||
|
||||
def test_loop_errors(self):
|
||||
tmpl = env.from_string('''{% for item in [1] if loop.index
|
||||
== 0 %}...{% endfor %}''')
|
||||
self.assert_raises(UndefinedError, tmpl.render)
|
||||
tmpl = env.from_string('''{% for item in [] %}...{% else
|
||||
%}{{ loop }}{% endfor %}''')
|
||||
assert tmpl.render() == ''
|
||||
|
||||
def test_loop_filter(self):
|
||||
tmpl = env.from_string('{% for item in range(10) if item '
|
||||
'is even %}[{{ item }}]{% endfor %}')
|
||||
assert tmpl.render() == '[0][2][4][6][8]'
|
||||
tmpl = env.from_string('''
|
||||
{%- for item in range(10) if item is even %}[{{
|
||||
loop.index }}:{{ item }}]{% endfor %}''')
|
||||
assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
|
||||
|
||||
def test_loop_unassignable(self):
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||||
'{% for loop in seq %}...{% endfor %}')
|
||||
|
||||
def test_scoped_special_var(self):
|
||||
t = env.from_string('{% for s in seq %}[{{ loop.first }}{% for c in s %}'
|
||||
'|{{ loop.first }}{% endfor %}]{% endfor %}')
|
||||
assert t.render(seq=('ab', 'cd')) == '[True|True|False][False|True|False]'
|
||||
|
||||
def test_scoped_loop_var(self):
|
||||
t = env.from_string('{% for x in seq %}{{ loop.first }}'
|
||||
'{% for y in seq %}{% endfor %}{% endfor %}')
|
||||
assert t.render(seq='ab') == 'TrueFalse'
|
||||
t = env.from_string('{% for x in seq %}{% for y in seq %}'
|
||||
'{{ loop.first }}{% endfor %}{% endfor %}')
|
||||
assert t.render(seq='ab') == 'TrueFalseTrueFalse'
|
||||
|
||||
def test_recursive_empty_loop_iter(self):
|
||||
t = env.from_string('''
|
||||
{%- for item in foo recursive -%}{%- endfor -%}
|
||||
''')
|
||||
assert t.render(dict(foo=[])) == ''
|
||||
|
||||
def test_call_in_loop(self):
|
||||
t = env.from_string('''
|
||||
{%- macro do_something() -%}
|
||||
[{{ caller() }}]
|
||||
{%- endmacro %}
|
||||
|
||||
{%- for i in [1, 2, 3] %}
|
||||
{%- call do_something() -%}
|
||||
{{ i }}
|
||||
{%- endcall %}
|
||||
{%- endfor -%}
|
||||
''')
|
||||
assert t.render() == '[1][2][3]'
|
||||
|
||||
def test_scoping_bug(self):
|
||||
t = env.from_string('''
|
||||
{%- for item in foo %}...{{ item }}...{% endfor %}
|
||||
{%- macro item(a) %}...{{ a }}...{% endmacro %}
|
||||
{{- item(2) -}}
|
||||
''')
|
||||
assert t.render(foo=(1,)) == '...1......2...'
|
||||
|
||||
def test_unpacking(self):
|
||||
tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}'
|
||||
'{{ a }}|{{ b }}|{{ c }}{% endfor %}')
|
||||
assert tmpl.render() == '1|2|3'
|
||||
|
||||
|
||||
class IfConditionTestCase(JinjaTestCase):
|
||||
|
||||
def test_simple(self):
|
||||
tmpl = env.from_string('''{% if true %}...{% endif %}''')
|
||||
assert tmpl.render() == '...'
|
||||
|
||||
def test_elif(self):
|
||||
tmpl = env.from_string('''{% if false %}XXX{% elif true
|
||||
%}...{% else %}XXX{% endif %}''')
|
||||
assert tmpl.render() == '...'
|
||||
|
||||
def test_else(self):
|
||||
tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
|
||||
assert tmpl.render() == '...'
|
||||
|
||||
def test_empty(self):
|
||||
tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]')
|
||||
assert tmpl.render() == '[]'
|
||||
|
||||
def test_complete(self):
|
||||
tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}'
|
||||
'C{% else %}D{% endif %}')
|
||||
assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C'
|
||||
|
||||
def test_no_scope(self):
|
||||
tmpl = env.from_string('{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}')
|
||||
assert tmpl.render(a=True) == '1'
|
||||
tmpl = env.from_string('{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}')
|
||||
assert tmpl.render() == '1'
|
||||
|
||||
|
||||
class MacrosTestCase(JinjaTestCase):
|
||||
env = Environment(trim_blocks=True)
|
||||
|
||||
def test_simple(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
|
||||
{{ say_hello('Peter') }}''')
|
||||
assert tmpl.render() == 'Hello Peter!'
|
||||
|
||||
def test_scoping(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% macro level1(data1) %}
|
||||
{% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
|
||||
{{ level2('bar') }}{% endmacro %}
|
||||
{{ level1('foo') }}''')
|
||||
assert tmpl.render() == 'foo|bar'
|
||||
|
||||
def test_arguments(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
|
||||
{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''')
|
||||
assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d'
|
||||
|
||||
def test_varargs(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
|
||||
{{ test(1, 2, 3) }}''')
|
||||
assert tmpl.render() == '1|2|3'
|
||||
|
||||
def test_simple_call(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% macro test() %}[[{{ caller() }}]]{% endmacro %}\
|
||||
{% call test() %}data{% endcall %}''')
|
||||
assert tmpl.render() == '[[data]]'
|
||||
|
||||
def test_complex_call(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
|
||||
{% call(data) test() %}{{ data }}{% endcall %}''')
|
||||
assert tmpl.render() == '[[data]]'
|
||||
|
||||
def test_caller_undefined(self):
|
||||
tmpl = self.env.from_string('''\
|
||||
{% set caller = 42 %}\
|
||||
{% macro test() %}{{ caller is not defined }}{% endmacro %}\
|
||||
{{ test() }}''')
|
||||
assert tmpl.render() == 'True'
|
||||
|
||||
def test_include(self):
|
||||
self.env = Environment(loader=DictLoader({'include':
|
||||
'{% macro test(foo) %}[{{ foo }}]{% endmacro %}'}))
|
||||
tmpl = self.env.from_string('{% from "include" import test %}{{ test("foo") }}')
|
||||
assert tmpl.render() == '[foo]'
|
||||
|
||||
def test_macro_api(self):
|
||||
tmpl = self.env.from_string('{% macro foo(a, b) %}{% endmacro %}'
|
||||
'{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}'
|
||||
'{% macro baz() %}{{ caller() }}{% endmacro %}')
|
||||
assert tmpl.module.foo.arguments == ('a', 'b')
|
||||
assert tmpl.module.foo.defaults == ()
|
||||
assert tmpl.module.foo.name == 'foo'
|
||||
assert not tmpl.module.foo.caller
|
||||
assert not tmpl.module.foo.catch_kwargs
|
||||
assert not tmpl.module.foo.catch_varargs
|
||||
assert tmpl.module.bar.arguments == ()
|
||||
assert tmpl.module.bar.defaults == ()
|
||||
assert not tmpl.module.bar.caller
|
||||
assert tmpl.module.bar.catch_kwargs
|
||||
assert tmpl.module.bar.catch_varargs
|
||||
assert tmpl.module.baz.caller
|
||||
|
||||
def test_callself(self):
|
||||
tmpl = self.env.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|'
|
||||
'{{ foo(x - 1) }}{% endif %}{% endmacro %}'
|
||||
'{{ foo(5) }}')
|
||||
assert tmpl.render() == '5|4|3|2|1'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ForLoopTestCase))
|
||||
suite.addTest(unittest.makeSuite(IfConditionTestCase))
|
||||
suite.addTest(unittest.makeSuite(MacrosTestCase))
|
||||
return suite
|
@ -1,60 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.debug
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the debug system.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase, filesystem_loader
|
||||
|
||||
from jinja2 import Environment, TemplateSyntaxError
|
||||
|
||||
env = Environment(loader=filesystem_loader)
|
||||
|
||||
|
||||
class DebugTestCase(JinjaTestCase):
|
||||
|
||||
if sys.version_info[:2] != (2, 4):
|
||||
def test_runtime_error(self):
|
||||
def test():
|
||||
tmpl.render(fail=lambda: 1 / 0)
|
||||
tmpl = env.get_template('broken.html')
|
||||
self.assert_traceback_matches(test, r'''
|
||||
File ".*?broken.html", line 2, in (top-level template code|<module>)
|
||||
\{\{ fail\(\) \}\}
|
||||
File ".*?debug.pyc?", line \d+, in <lambda>
|
||||
tmpl\.render\(fail=lambda: 1 / 0\)
|
||||
ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
|
||||
''')
|
||||
|
||||
def test_syntax_error(self):
|
||||
# XXX: the .*? is necessary for python3 which does not hide
|
||||
# some of the stack frames we don't want to show. Not sure
|
||||
# what's up with that, but that is not that critical. Should
|
||||
# be fixed though.
|
||||
self.assert_traceback_matches(lambda: env.get_template('syntaxerror.html'), r'''(?sm)
|
||||
File ".*?syntaxerror.html", line 4, in (template|<module>)
|
||||
\{% endif %\}.*?
|
||||
(jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'.
|
||||
''')
|
||||
|
||||
def test_regular_syntax_error(self):
|
||||
def test():
|
||||
raise TemplateSyntaxError('wtf', 42)
|
||||
self.assert_traceback_matches(test, r'''
|
||||
File ".*debug.pyc?", line \d+, in test
|
||||
raise TemplateSyntaxError\('wtf', 42\)
|
||||
(jinja2\.exceptions\.)?TemplateSyntaxError: wtf
|
||||
line 42''')
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(DebugTestCase))
|
||||
return suite
|
@ -1,29 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.doctests
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The doctests. Collects all tests we want to test from
|
||||
the Jinja modules.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
import doctest
|
||||
|
||||
|
||||
def suite():
|
||||
from jinja2 import utils, sandbox, runtime, meta, loaders, \
|
||||
ext, environment, bccache, nodes
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(doctest.DocTestSuite(utils))
|
||||
suite.addTest(doctest.DocTestSuite(sandbox))
|
||||
suite.addTest(doctest.DocTestSuite(runtime))
|
||||
suite.addTest(doctest.DocTestSuite(meta))
|
||||
suite.addTest(doctest.DocTestSuite(loaders))
|
||||
suite.addTest(doctest.DocTestSuite(ext))
|
||||
suite.addTest(doctest.DocTestSuite(environment))
|
||||
suite.addTest(doctest.DocTestSuite(bccache))
|
||||
suite.addTest(doctest.DocTestSuite(nodes))
|
||||
return suite
|
@ -1,455 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.ext
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests for the extensions.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import re
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment, DictLoader, contextfunction, nodes
|
||||
from jinja2.exceptions import TemplateAssertionError
|
||||
from jinja2.ext import Extension
|
||||
from jinja2.lexer import Token, count_newlines
|
||||
from jinja2.utils import next
|
||||
|
||||
# 2.x / 3.x
|
||||
try:
|
||||
from io import BytesIO
|
||||
except ImportError:
|
||||
from StringIO import StringIO as BytesIO
|
||||
|
||||
|
||||
importable_object = 23
|
||||
|
||||
_gettext_re = re.compile(r'_\((.*?)\)(?s)')
|
||||
|
||||
|
||||
i18n_templates = {
|
||||
'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
|
||||
'{% block body %}{% endblock %}',
|
||||
'child.html': '{% extends "master.html" %}{% block body %}'
|
||||
'{% trans %}watch out{% endtrans %}{% endblock %}',
|
||||
'plural.html': '{% trans user_count %}One user online{% pluralize %}'
|
||||
'{{ user_count }} users online{% endtrans %}',
|
||||
'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}'
|
||||
}
|
||||
|
||||
newstyle_i18n_templates = {
|
||||
'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
|
||||
'{% block body %}{% endblock %}',
|
||||
'child.html': '{% extends "master.html" %}{% block body %}'
|
||||
'{% trans %}watch out{% endtrans %}{% endblock %}',
|
||||
'plural.html': '{% trans user_count %}One user online{% pluralize %}'
|
||||
'{{ user_count }} users online{% endtrans %}',
|
||||
'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}',
|
||||
'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}',
|
||||
'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}'
|
||||
'{{ num }} apples{% endtrans %}',
|
||||
'transvars1.html': '{% trans %}User: {{ num }}{% endtrans %}',
|
||||
'transvars2.html': '{% trans num=count %}User: {{ num }}{% endtrans %}',
|
||||
'transvars3.html': '{% trans count=num %}User: {{ count }}{% endtrans %}',
|
||||
'novars.html': '{% trans %}%(hello)s{% endtrans %}',
|
||||
'vars.html': '{% trans %}{{ foo }}%(foo)s{% endtrans %}',
|
||||
'explicitvars.html': '{% trans foo="42" %}%(foo)s{% endtrans %}'
|
||||
}
|
||||
|
||||
|
||||
languages = {
|
||||
'de': {
|
||||
'missing': u'fehlend',
|
||||
'watch out': u'pass auf',
|
||||
'One user online': u'Ein Benutzer online',
|
||||
'%(user_count)s users online': u'%(user_count)s Benutzer online',
|
||||
'User: %(num)s': u'Benutzer: %(num)s',
|
||||
'User: %(count)s': u'Benutzer: %(count)s',
|
||||
'%(num)s apple': u'%(num)s Apfel',
|
||||
'%(num)s apples': u'%(num)s Äpfel'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@contextfunction
|
||||
def gettext(context, string):
|
||||
language = context.get('LANGUAGE', 'en')
|
||||
return languages.get(language, {}).get(string, string)
|
||||
|
||||
|
||||
@contextfunction
|
||||
def ngettext(context, s, p, n):
|
||||
language = context.get('LANGUAGE', 'en')
|
||||
if n != 1:
|
||||
return languages.get(language, {}).get(p, p)
|
||||
return languages.get(language, {}).get(s, s)
|
||||
|
||||
|
||||
i18n_env = Environment(
|
||||
loader=DictLoader(i18n_templates),
|
||||
extensions=['jinja2.ext.i18n']
|
||||
)
|
||||
i18n_env.globals.update({
|
||||
'_': gettext,
|
||||
'gettext': gettext,
|
||||
'ngettext': ngettext
|
||||
})
|
||||
|
||||
newstyle_i18n_env = Environment(
|
||||
loader=DictLoader(newstyle_i18n_templates),
|
||||
extensions=['jinja2.ext.i18n']
|
||||
)
|
||||
newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True)
|
||||
|
||||
class TestExtension(Extension):
|
||||
tags = set(['test'])
|
||||
ext_attr = 42
|
||||
|
||||
def parse(self, parser):
|
||||
return nodes.Output([self.call_method('_dump', [
|
||||
nodes.EnvironmentAttribute('sandboxed'),
|
||||
self.attr('ext_attr'),
|
||||
nodes.ImportedName(__name__ + '.importable_object'),
|
||||
nodes.ContextReference()
|
||||
])]).set_lineno(next(parser.stream).lineno)
|
||||
|
||||
def _dump(self, sandboxed, ext_attr, imported_object, context):
|
||||
return '%s|%s|%s|%s' % (
|
||||
sandboxed,
|
||||
ext_attr,
|
||||
imported_object,
|
||||
context.blocks
|
||||
)
|
||||
|
||||
|
||||
class PreprocessorExtension(Extension):
|
||||
|
||||
def preprocess(self, source, name, filename=None):
|
||||
return source.replace('[[TEST]]', '({{ foo }})')
|
||||
|
||||
|
||||
class StreamFilterExtension(Extension):
|
||||
|
||||
def filter_stream(self, stream):
|
||||
for token in stream:
|
||||
if token.type == 'data':
|
||||
for t in self.interpolate(token):
|
||||
yield t
|
||||
else:
|
||||
yield token
|
||||
|
||||
def interpolate(self, token):
|
||||
pos = 0
|
||||
end = len(token.value)
|
||||
lineno = token.lineno
|
||||
while 1:
|
||||
match = _gettext_re.search(token.value, pos)
|
||||
if match is None:
|
||||
break
|
||||
value = token.value[pos:match.start()]
|
||||
if value:
|
||||
yield Token(lineno, 'data', value)
|
||||
lineno += count_newlines(token.value)
|
||||
yield Token(lineno, 'variable_begin', None)
|
||||
yield Token(lineno, 'name', 'gettext')
|
||||
yield Token(lineno, 'lparen', None)
|
||||
yield Token(lineno, 'string', match.group(1))
|
||||
yield Token(lineno, 'rparen', None)
|
||||
yield Token(lineno, 'variable_end', None)
|
||||
pos = match.end()
|
||||
if pos < end:
|
||||
yield Token(lineno, 'data', token.value[pos:])
|
||||
|
||||
|
||||
class ExtensionsTestCase(JinjaTestCase):
|
||||
|
||||
def test_extend_late(self):
|
||||
env = Environment()
|
||||
env.add_extension('jinja2.ext.autoescape')
|
||||
t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
|
||||
assert t.render() == '<test>'
|
||||
|
||||
def test_loop_controls(self):
|
||||
env = Environment(extensions=['jinja2.ext.loopcontrols'])
|
||||
|
||||
tmpl = env.from_string('''
|
||||
{%- for item in [1, 2, 3, 4] %}
|
||||
{%- if item % 2 == 0 %}{% continue %}{% endif -%}
|
||||
{{ item }}
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render() == '13'
|
||||
|
||||
tmpl = env.from_string('''
|
||||
{%- for item in [1, 2, 3, 4] %}
|
||||
{%- if item > 2 %}{% break %}{% endif -%}
|
||||
{{ item }}
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render() == '12'
|
||||
|
||||
def test_do(self):
|
||||
env = Environment(extensions=['jinja2.ext.do'])
|
||||
tmpl = env.from_string('''
|
||||
{%- set items = [] %}
|
||||
{%- for char in "foo" %}
|
||||
{%- do items.append(loop.index0 ~ char) %}
|
||||
{%- endfor %}{{ items|join(', ') }}''')
|
||||
assert tmpl.render() == '0f, 1o, 2o'
|
||||
|
||||
def test_with(self):
|
||||
env = Environment(extensions=['jinja2.ext.with_'])
|
||||
tmpl = env.from_string('''\
|
||||
{% with a=42, b=23 -%}
|
||||
{{ a }} = {{ b }}
|
||||
{% endwith -%}
|
||||
{{ a }} = {{ b }}\
|
||||
''')
|
||||
assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \
|
||||
== ['42 = 23', '1 = 2']
|
||||
|
||||
def test_extension_nodes(self):
|
||||
env = Environment(extensions=[TestExtension])
|
||||
tmpl = env.from_string('{% test %}')
|
||||
assert tmpl.render() == 'False|42|23|{}'
|
||||
|
||||
def test_identifier(self):
|
||||
assert TestExtension.identifier == __name__ + '.TestExtension'
|
||||
|
||||
def test_rebinding(self):
|
||||
original = Environment(extensions=[TestExtension])
|
||||
overlay = original.overlay()
|
||||
for env in original, overlay:
|
||||
for ext in env.extensions.itervalues():
|
||||
assert ext.environment is env
|
||||
|
||||
def test_preprocessor_extension(self):
|
||||
env = Environment(extensions=[PreprocessorExtension])
|
||||
tmpl = env.from_string('{[[TEST]]}')
|
||||
assert tmpl.render(foo=42) == '{(42)}'
|
||||
|
||||
def test_streamfilter_extension(self):
|
||||
env = Environment(extensions=[StreamFilterExtension])
|
||||
env.globals['gettext'] = lambda x: x.upper()
|
||||
tmpl = env.from_string('Foo _(bar) Baz')
|
||||
out = tmpl.render()
|
||||
assert out == 'Foo BAR Baz'
|
||||
|
||||
def test_extension_ordering(self):
|
||||
class T1(Extension):
|
||||
priority = 1
|
||||
class T2(Extension):
|
||||
priority = 2
|
||||
env = Environment(extensions=[T1, T2])
|
||||
ext = list(env.iter_extensions())
|
||||
assert ext[0].__class__ is T1
|
||||
assert ext[1].__class__ is T2
|
||||
|
||||
|
||||
class InternationalizationTestCase(JinjaTestCase):
|
||||
|
||||
def test_trans(self):
|
||||
tmpl = i18n_env.get_template('child.html')
|
||||
assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
|
||||
|
||||
def test_trans_plural(self):
|
||||
tmpl = i18n_env.get_template('plural.html')
|
||||
assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online'
|
||||
assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
|
||||
|
||||
def test_complex_plural(self):
|
||||
tmpl = i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% '
|
||||
'pluralize count %}{{ count }} items{% endtrans %}')
|
||||
assert tmpl.render() == '2 items'
|
||||
self.assert_raises(TemplateAssertionError, i18n_env.from_string,
|
||||
'{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
|
||||
|
||||
def test_trans_stringformatting(self):
|
||||
tmpl = i18n_env.get_template('stringformat.html')
|
||||
assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
|
||||
|
||||
def test_extract(self):
|
||||
from jinja2.ext import babel_extract
|
||||
source = BytesIO('''
|
||||
{{ gettext('Hello World') }}
|
||||
{% trans %}Hello World{% endtrans %}
|
||||
{% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
|
||||
'''.encode('ascii')) # make python 3 happy
|
||||
assert list(babel_extract(source, ('gettext', 'ngettext', '_'), [], {})) == [
|
||||
(2, 'gettext', u'Hello World', []),
|
||||
(3, 'gettext', u'Hello World', []),
|
||||
(4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), [])
|
||||
]
|
||||
|
||||
def test_comment_extract(self):
|
||||
from jinja2.ext import babel_extract
|
||||
source = BytesIO('''
|
||||
{# trans first #}
|
||||
{{ gettext('Hello World') }}
|
||||
{% trans %}Hello World{% endtrans %}{# trans second #}
|
||||
{#: third #}
|
||||
{% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
|
||||
'''.encode('utf-8')) # make python 3 happy
|
||||
assert list(babel_extract(source, ('gettext', 'ngettext', '_'), ['trans', ':'], {})) == [
|
||||
(3, 'gettext', u'Hello World', ['first']),
|
||||
(4, 'gettext', u'Hello World', ['second']),
|
||||
(6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), ['third'])
|
||||
]
|
||||
|
||||
|
||||
class NewstyleInternationalizationTestCase(JinjaTestCase):
|
||||
|
||||
def test_trans(self):
|
||||
tmpl = newstyle_i18n_env.get_template('child.html')
|
||||
assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
|
||||
|
||||
def test_trans_plural(self):
|
||||
tmpl = newstyle_i18n_env.get_template('plural.html')
|
||||
assert tmpl.render(LANGUAGE='de', user_count=1) == 'Ein Benutzer online'
|
||||
assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
|
||||
|
||||
def test_complex_plural(self):
|
||||
tmpl = newstyle_i18n_env.from_string('{% trans foo=42, count=2 %}{{ count }} item{% '
|
||||
'pluralize count %}{{ count }} items{% endtrans %}')
|
||||
assert tmpl.render() == '2 items'
|
||||
self.assert_raises(TemplateAssertionError, i18n_env.from_string,
|
||||
'{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
|
||||
|
||||
def test_trans_stringformatting(self):
|
||||
tmpl = newstyle_i18n_env.get_template('stringformat.html')
|
||||
assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
|
||||
|
||||
def test_newstyle_plural(self):
|
||||
tmpl = newstyle_i18n_env.get_template('ngettext.html')
|
||||
assert tmpl.render(LANGUAGE='de', apples=1) == '1 Apfel'
|
||||
assert tmpl.render(LANGUAGE='de', apples=5) == u'5 Äpfel'
|
||||
|
||||
def test_autoescape_support(self):
|
||||
env = Environment(extensions=['jinja2.ext.autoescape',
|
||||
'jinja2.ext.i18n'])
|
||||
env.install_gettext_callables(lambda x: u'<strong>Wert: %(name)s</strong>',
|
||||
lambda s, p, n: s, newstyle=True)
|
||||
t = env.from_string('{% autoescape ae %}{{ gettext("foo", name='
|
||||
'"<test>") }}{% endautoescape %}')
|
||||
assert t.render(ae=True) == '<strong>Wert: <test></strong>'
|
||||
assert t.render(ae=False) == '<strong>Wert: <test></strong>'
|
||||
|
||||
def test_num_used_twice(self):
|
||||
tmpl = newstyle_i18n_env.get_template('ngettext_long.html')
|
||||
assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel'
|
||||
|
||||
def test_num_called_num(self):
|
||||
source = newstyle_i18n_env.compile('''
|
||||
{% trans num=3 %}{{ num }} apple{% pluralize
|
||||
%}{{ num }} apples{% endtrans %}
|
||||
''', raw=True)
|
||||
# quite hacky, but the only way to properly test that. The idea is
|
||||
# that the generated code does not pass num twice (although that
|
||||
# would work) for better performance. This only works on the
|
||||
# newstyle gettext of course
|
||||
assert re.search(r"l_ngettext, u?'\%\(num\)s apple', u?'\%\(num\)s "
|
||||
r"apples', 3", source) is not None
|
||||
|
||||
def test_trans_vars(self):
|
||||
t1 = newstyle_i18n_env.get_template('transvars1.html')
|
||||
t2 = newstyle_i18n_env.get_template('transvars2.html')
|
||||
t3 = newstyle_i18n_env.get_template('transvars3.html')
|
||||
assert t1.render(num=1, LANGUAGE='de') == 'Benutzer: 1'
|
||||
assert t2.render(count=23, LANGUAGE='de') == 'Benutzer: 23'
|
||||
assert t3.render(num=42, LANGUAGE='de') == 'Benutzer: 42'
|
||||
|
||||
def test_novars_vars_escaping(self):
|
||||
t = newstyle_i18n_env.get_template('novars.html')
|
||||
assert t.render() == '%(hello)s'
|
||||
t = newstyle_i18n_env.get_template('vars.html')
|
||||
assert t.render(foo='42') == '42%(foo)s'
|
||||
t = newstyle_i18n_env.get_template('explicitvars.html')
|
||||
assert t.render() == '%(foo)s'
|
||||
|
||||
|
||||
class AutoEscapeTestCase(JinjaTestCase):
|
||||
|
||||
def test_scoped_setting(self):
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'],
|
||||
autoescape=True)
|
||||
tmpl = env.from_string('''
|
||||
{{ "<HelloWorld>" }}
|
||||
{% autoescape false %}
|
||||
{{ "<HelloWorld>" }}
|
||||
{% endautoescape %}
|
||||
{{ "<HelloWorld>" }}
|
||||
''')
|
||||
assert tmpl.render().split() == \
|
||||
[u'<HelloWorld>', u'<HelloWorld>', u'<HelloWorld>']
|
||||
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'],
|
||||
autoescape=False)
|
||||
tmpl = env.from_string('''
|
||||
{{ "<HelloWorld>" }}
|
||||
{% autoescape true %}
|
||||
{{ "<HelloWorld>" }}
|
||||
{% endautoescape %}
|
||||
{{ "<HelloWorld>" }}
|
||||
''')
|
||||
assert tmpl.render().split() == \
|
||||
[u'<HelloWorld>', u'<HelloWorld>', u'<HelloWorld>']
|
||||
|
||||
def test_nonvolatile(self):
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'],
|
||||
autoescape=True)
|
||||
tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
|
||||
assert tmpl.render() == ' foo="<test>"'
|
||||
tmpl = env.from_string('{% autoescape false %}{{ {"foo": "<test>"}'
|
||||
'|xmlattr|escape }}{% endautoescape %}')
|
||||
assert tmpl.render() == ' foo="&lt;test&gt;"'
|
||||
|
||||
def test_volatile(self):
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'],
|
||||
autoescape=True)
|
||||
tmpl = env.from_string('{% autoescape foo %}{{ {"foo": "<test>"}'
|
||||
'|xmlattr|escape }}{% endautoescape %}')
|
||||
assert tmpl.render(foo=False) == ' foo="&lt;test&gt;"'
|
||||
assert tmpl.render(foo=True) == ' foo="<test>"'
|
||||
|
||||
def test_scoping(self):
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'])
|
||||
tmpl = env.from_string('{% autoescape true %}{% set x = "<x>" %}{{ x }}'
|
||||
'{% endautoescape %}{{ x }}{{ "<y>" }}')
|
||||
assert tmpl.render(x=1) == '<x>1<y>'
|
||||
|
||||
def test_volatile_scoping(self):
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'])
|
||||
tmplsource = '''
|
||||
{% autoescape val %}
|
||||
{% macro foo(x) %}
|
||||
[{{ x }}]
|
||||
{% endmacro %}
|
||||
{{ foo().__class__.__name__ }}
|
||||
{% endautoescape %}
|
||||
{{ '<testing>' }}
|
||||
'''
|
||||
tmpl = env.from_string(tmplsource)
|
||||
assert tmpl.render(val=True).split()[0] == 'Markup'
|
||||
assert tmpl.render(val=False).split()[0] == unicode.__name__
|
||||
|
||||
# looking at the source we should see <testing> there in raw
|
||||
# (and then escaped as well)
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'])
|
||||
pysource = env.compile(tmplsource, raw=True)
|
||||
assert '<testing>\\n' in pysource
|
||||
|
||||
env = Environment(extensions=['jinja2.ext.autoescape'],
|
||||
autoescape=True)
|
||||
pysource = env.compile(tmplsource, raw=True)
|
||||
assert '<testing>\\n' in pysource
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ExtensionsTestCase))
|
||||
suite.addTest(unittest.makeSuite(InternationalizationTestCase))
|
||||
suite.addTest(unittest.makeSuite(NewstyleInternationalizationTestCase))
|
||||
suite.addTest(unittest.makeSuite(AutoEscapeTestCase))
|
||||
return suite
|
@ -1,396 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.filters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests for the jinja filters.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Markup, Environment
|
||||
|
||||
env = Environment()
|
||||
|
||||
|
||||
class FilterTestCase(JinjaTestCase):
|
||||
|
||||
def test_capitalize(self):
|
||||
tmpl = env.from_string('{{ "foo bar"|capitalize }}')
|
||||
assert tmpl.render() == 'Foo bar'
|
||||
|
||||
def test_center(self):
|
||||
tmpl = env.from_string('{{ "foo"|center(9) }}')
|
||||
assert tmpl.render() == ' foo '
|
||||
|
||||
def test_default(self):
|
||||
tmpl = env.from_string(
|
||||
"{{ missing|default('no') }}|{{ false|default('no') }}|"
|
||||
"{{ false|default('no', true) }}|{{ given|default('no') }}"
|
||||
)
|
||||
assert tmpl.render(given='yes') == 'no|False|no|yes'
|
||||
|
||||
def test_dictsort(self):
|
||||
tmpl = env.from_string(
|
||||
'{{ foo|dictsort }}|'
|
||||
'{{ foo|dictsort(true) }}|'
|
||||
'{{ foo|dictsort(false, "value") }}'
|
||||
)
|
||||
out = tmpl.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
|
||||
assert out == ("[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]|"
|
||||
"[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]|"
|
||||
"[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]")
|
||||
|
||||
def test_batch(self):
|
||||
tmpl = env.from_string("{{ foo|batch(3)|list }}|"
|
||||
"{{ foo|batch(3, 'X')|list }}")
|
||||
out = tmpl.render(foo=range(10))
|
||||
assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
|
||||
"[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]")
|
||||
|
||||
def test_slice(self):
|
||||
tmpl = env.from_string('{{ foo|slice(3)|list }}|'
|
||||
'{{ foo|slice(3, "X")|list }}')
|
||||
out = tmpl.render(foo=range(10))
|
||||
assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
|
||||
"[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]")
|
||||
|
||||
def test_escape(self):
|
||||
tmpl = env.from_string('''{{ '<">&'|escape }}''')
|
||||
out = tmpl.render()
|
||||
assert out == '<">&'
|
||||
|
||||
def test_striptags(self):
|
||||
tmpl = env.from_string('''{{ foo|striptags }}''')
|
||||
out = tmpl.render(foo=' <p>just a small \n <a href="#">'
|
||||
'example</a> link</p>\n<p>to a webpage</p> '
|
||||
'<!-- <p>and some commented stuff</p> -->')
|
||||
assert out == 'just a small example link to a webpage'
|
||||
|
||||
def test_filesizeformat(self):
|
||||
tmpl = env.from_string(
|
||||
'{{ 100|filesizeformat }}|'
|
||||
'{{ 1000|filesizeformat }}|'
|
||||
'{{ 1000000|filesizeformat }}|'
|
||||
'{{ 1000000000|filesizeformat }}|'
|
||||
'{{ 1000000000000|filesizeformat }}|'
|
||||
'{{ 100|filesizeformat(true) }}|'
|
||||
'{{ 1000|filesizeformat(true) }}|'
|
||||
'{{ 1000000|filesizeformat(true) }}|'
|
||||
'{{ 1000000000|filesizeformat(true) }}|'
|
||||
'{{ 1000000000000|filesizeformat(true) }}'
|
||||
)
|
||||
out = tmpl.render()
|
||||
self.assert_equal(out, (
|
||||
'100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|'
|
||||
'1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB'
|
||||
))
|
||||
|
||||
def test_filesizeformat_issue59(self):
|
||||
tmpl = env.from_string(
|
||||
'{{ 300|filesizeformat }}|'
|
||||
'{{ 3000|filesizeformat }}|'
|
||||
'{{ 3000000|filesizeformat }}|'
|
||||
'{{ 3000000000|filesizeformat }}|'
|
||||
'{{ 3000000000000|filesizeformat }}|'
|
||||
'{{ 300|filesizeformat(true) }}|'
|
||||
'{{ 3000|filesizeformat(true) }}|'
|
||||
'{{ 3000000|filesizeformat(true) }}'
|
||||
)
|
||||
out = tmpl.render()
|
||||
self.assert_equal(out, (
|
||||
'300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|'
|
||||
'2.9 KiB|2.9 MiB'
|
||||
))
|
||||
|
||||
|
||||
def test_first(self):
|
||||
tmpl = env.from_string('{{ foo|first }}')
|
||||
out = tmpl.render(foo=range(10))
|
||||
assert out == '0'
|
||||
|
||||
def test_float(self):
|
||||
tmpl = env.from_string('{{ "42"|float }}|'
|
||||
'{{ "ajsghasjgd"|float }}|'
|
||||
'{{ "32.32"|float }}')
|
||||
out = tmpl.render()
|
||||
assert out == '42.0|0.0|32.32'
|
||||
|
||||
def test_format(self):
|
||||
tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''')
|
||||
out = tmpl.render()
|
||||
assert out == 'a|b'
|
||||
|
||||
def test_indent(self):
|
||||
tmpl = env.from_string('{{ foo|indent(2) }}|{{ foo|indent(2, true) }}')
|
||||
text = '\n'.join([' '.join(['foo', 'bar'] * 2)] * 2)
|
||||
out = tmpl.render(foo=text)
|
||||
assert out == ('foo bar foo bar\n foo bar foo bar| '
|
||||
'foo bar foo bar\n foo bar foo bar')
|
||||
|
||||
def test_int(self):
|
||||
tmpl = env.from_string('{{ "42"|int }}|{{ "ajsghasjgd"|int }}|'
|
||||
'{{ "32.32"|int }}')
|
||||
out = tmpl.render()
|
||||
assert out == '42|0|32'
|
||||
|
||||
def test_join(self):
|
||||
tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
|
||||
out = tmpl.render()
|
||||
assert out == '1|2|3'
|
||||
|
||||
env2 = Environment(autoescape=True)
|
||||
tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
|
||||
assert tmpl.render() == '<foo><span>foo</span>'
|
||||
|
||||
def test_join_attribute(self):
|
||||
class User(object):
|
||||
def __init__(self, username):
|
||||
self.username = username
|
||||
tmpl = env.from_string('''{{ users|join(', ', 'username') }}''')
|
||||
assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar'
|
||||
|
||||
def test_last(self):
|
||||
tmpl = env.from_string('''{{ foo|last }}''')
|
||||
out = tmpl.render(foo=range(10))
|
||||
assert out == '9'
|
||||
|
||||
def test_length(self):
|
||||
tmpl = env.from_string('''{{ "hello world"|length }}''')
|
||||
out = tmpl.render()
|
||||
assert out == '11'
|
||||
|
||||
def test_lower(self):
|
||||
tmpl = env.from_string('''{{ "FOO"|lower }}''')
|
||||
out = tmpl.render()
|
||||
assert out == 'foo'
|
||||
|
||||
def test_pprint(self):
|
||||
from pprint import pformat
|
||||
tmpl = env.from_string('''{{ data|pprint }}''')
|
||||
data = range(1000)
|
||||
assert tmpl.render(data=data) == pformat(data)
|
||||
|
||||
def test_random(self):
|
||||
tmpl = env.from_string('''{{ seq|random }}''')
|
||||
seq = range(100)
|
||||
for _ in range(10):
|
||||
assert int(tmpl.render(seq=seq)) in seq
|
||||
|
||||
def test_reverse(self):
|
||||
tmpl = env.from_string('{{ "foobar"|reverse|join }}|'
|
||||
'{{ [1, 2, 3]|reverse|list }}')
|
||||
assert tmpl.render() == 'raboof|[3, 2, 1]'
|
||||
|
||||
def test_string(self):
|
||||
x = [1, 2, 3, 4, 5]
|
||||
tmpl = env.from_string('''{{ obj|string }}''')
|
||||
assert tmpl.render(obj=x) == unicode(x)
|
||||
|
||||
def test_title(self):
|
||||
tmpl = env.from_string('''{{ "foo bar"|title }}''')
|
||||
assert tmpl.render() == "Foo Bar"
|
||||
tmpl = env.from_string('''{{ "foo's bar"|title }}''')
|
||||
assert tmpl.render() == "Foo's Bar"
|
||||
tmpl = env.from_string('''{{ "foo bar"|title }}''')
|
||||
assert tmpl.render() == "Foo Bar"
|
||||
tmpl = env.from_string('''{{ "f bar f"|title }}''')
|
||||
assert tmpl.render() == "F Bar F"
|
||||
tmpl = env.from_string('''{{ "foo-bar"|title }}''')
|
||||
assert tmpl.render() == "Foo-Bar"
|
||||
tmpl = env.from_string('''{{ "foo\tbar"|title }}''')
|
||||
assert tmpl.render() == "Foo\tBar"
|
||||
|
||||
def test_truncate(self):
|
||||
tmpl = env.from_string(
|
||||
'{{ data|truncate(15, true, ">>>") }}|'
|
||||
'{{ data|truncate(15, false, ">>>") }}|'
|
||||
'{{ smalldata|truncate(15) }}'
|
||||
)
|
||||
out = tmpl.render(data='foobar baz bar' * 1000,
|
||||
smalldata='foobar baz bar')
|
||||
assert out == 'foobar baz barf>>>|foobar baz >>>|foobar baz bar'
|
||||
|
||||
def test_upper(self):
|
||||
tmpl = env.from_string('{{ "foo"|upper }}')
|
||||
assert tmpl.render() == 'FOO'
|
||||
|
||||
def test_urlize(self):
|
||||
tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
|
||||
assert tmpl.render() == 'foo <a href="http://www.example.com/">'\
|
||||
'http://www.example.com/</a> bar'
|
||||
|
||||
def test_wordcount(self):
|
||||
tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
|
||||
assert tmpl.render() == '3'
|
||||
|
||||
def test_block(self):
|
||||
tmpl = env.from_string('{% filter lower|escape %}<HEHE>{% endfilter %}')
|
||||
assert tmpl.render() == '<hehe>'
|
||||
|
||||
def test_chaining(self):
|
||||
tmpl = env.from_string('''{{ ['<foo>', '<bar>']|first|upper|escape }}''')
|
||||
assert tmpl.render() == '<FOO>'
|
||||
|
||||
def test_sum(self):
|
||||
tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''')
|
||||
assert tmpl.render() == '21'
|
||||
|
||||
def test_sum_attributes(self):
|
||||
tmpl = env.from_string('''{{ values|sum('value') }}''')
|
||||
assert tmpl.render(values=[
|
||||
{'value': 23},
|
||||
{'value': 1},
|
||||
{'value': 18},
|
||||
]) == '42'
|
||||
|
||||
def test_sum_attributes_nested(self):
|
||||
tmpl = env.from_string('''{{ values|sum('real.value') }}''')
|
||||
assert tmpl.render(values=[
|
||||
{'real': {'value': 23}},
|
||||
{'real': {'value': 1}},
|
||||
{'real': {'value': 18}},
|
||||
]) == '42'
|
||||
|
||||
def test_abs(self):
|
||||
tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''')
|
||||
assert tmpl.render() == '1|1', tmpl.render()
|
||||
|
||||
def test_round_positive(self):
|
||||
tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|'
|
||||
"{{ 2.1234|round(3, 'floor') }}|"
|
||||
"{{ 2.1|round(0, 'ceil') }}")
|
||||
assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render()
|
||||
|
||||
def test_round_negative(self):
|
||||
tmpl = env.from_string('{{ 21.3|round(-1)}}|'
|
||||
"{{ 21.3|round(-1, 'ceil')}}|"
|
||||
"{{ 21.3|round(-1, 'floor')}}")
|
||||
assert tmpl.render() == '20.0|30.0|20.0',tmpl.render()
|
||||
|
||||
def test_xmlattr(self):
|
||||
tmpl = env.from_string("{{ {'foo': 42, 'bar': 23, 'fish': none, "
|
||||
"'spam': missing, 'blub:blub': '<?>'}|xmlattr }}")
|
||||
out = tmpl.render().split()
|
||||
assert len(out) == 3
|
||||
assert 'foo="42"' in out
|
||||
assert 'bar="23"' in out
|
||||
assert 'blub:blub="<?>"' in out
|
||||
|
||||
def test_sort1(self):
|
||||
tmpl = env.from_string('{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}')
|
||||
assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
|
||||
|
||||
def test_sort2(self):
|
||||
tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
|
||||
assert tmpl.render() == 'AbcD'
|
||||
|
||||
def test_sort3(self):
|
||||
tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''')
|
||||
assert tmpl.render() == "['Bar', 'blah', 'foo']"
|
||||
|
||||
def test_sort4(self):
|
||||
class Magic(object):
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
def __unicode__(self):
|
||||
return unicode(self.value)
|
||||
tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''')
|
||||
assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234'
|
||||
|
||||
def test_groupby(self):
|
||||
tmpl = env.from_string('''
|
||||
{%- for grouper, list in [{'foo': 1, 'bar': 2},
|
||||
{'foo': 2, 'bar': 3},
|
||||
{'foo': 1, 'bar': 1},
|
||||
{'foo': 3, 'bar': 4}]|groupby('foo') -%}
|
||||
{{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render().split('|') == [
|
||||
"1: 1, 2: 1, 1",
|
||||
"2: 2, 3",
|
||||
"3: 3, 4",
|
||||
""
|
||||
]
|
||||
|
||||
def test_groupby_tuple_index(self):
|
||||
tmpl = env.from_string('''
|
||||
{%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
|
||||
{{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render() == 'a:1:2|b:1|'
|
||||
|
||||
def test_groupby_multidot(self):
|
||||
class Date(object):
|
||||
def __init__(self, day, month, year):
|
||||
self.day = day
|
||||
self.month = month
|
||||
self.year = year
|
||||
class Article(object):
|
||||
def __init__(self, title, *date):
|
||||
self.date = Date(*date)
|
||||
self.title = title
|
||||
articles = [
|
||||
Article('aha', 1, 1, 1970),
|
||||
Article('interesting', 2, 1, 1970),
|
||||
Article('really?', 3, 1, 1970),
|
||||
Article('totally not', 1, 1, 1971)
|
||||
]
|
||||
tmpl = env.from_string('''
|
||||
{%- for year, list in articles|groupby('date.year') -%}
|
||||
{{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
|
||||
{%- endfor %}''')
|
||||
assert tmpl.render(articles=articles).split('|') == [
|
||||
'1970[aha][interesting][really?]',
|
||||
'1971[totally not]',
|
||||
''
|
||||
]
|
||||
|
||||
def test_filtertag(self):
|
||||
tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}"
|
||||
"foobar{% endfilter %}")
|
||||
assert tmpl.render() == 'fooBAR'
|
||||
|
||||
def test_replace(self):
|
||||
env = Environment()
|
||||
tmpl = env.from_string('{{ string|replace("o", 42) }}')
|
||||
assert tmpl.render(string='<foo>') == '<f4242>'
|
||||
env = Environment(autoescape=True)
|
||||
tmpl = env.from_string('{{ string|replace("o", 42) }}')
|
||||
assert tmpl.render(string='<foo>') == '<f4242>'
|
||||
tmpl = env.from_string('{{ string|replace("<", 42) }}')
|
||||
assert tmpl.render(string='<foo>') == '42foo>'
|
||||
tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
|
||||
assert tmpl.render(string=Markup('foo')) == 'f>x<>x<'
|
||||
|
||||
def test_forceescape(self):
|
||||
tmpl = env.from_string('{{ x|forceescape }}')
|
||||
assert tmpl.render(x=Markup('<div />')) == u'<div />'
|
||||
|
||||
def test_safe(self):
|
||||
env = Environment(autoescape=True)
|
||||
tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
|
||||
assert tmpl.render() == '<div>foo</div>'
|
||||
tmpl = env.from_string('{{ "<div>foo</div>" }}')
|
||||
assert tmpl.render() == '<div>foo</div>'
|
||||
|
||||
def test_urlencode(self):
|
||||
env = Environment(autoescape=True)
|
||||
tmpl = env.from_string('{{ "Hello, world!"|urlencode }}')
|
||||
assert tmpl.render() == 'Hello%2C%20world%21'
|
||||
tmpl = env.from_string('{{ o|urlencode }}')
|
||||
assert tmpl.render(o=u"Hello, world\u203d") == "Hello%2C%20world%E2%80%BD"
|
||||
assert tmpl.render(o=(("f", 1),)) == "f=1"
|
||||
assert tmpl.render(o=(('f', 1), ("z", 2))) == "f=1&z=2"
|
||||
assert tmpl.render(o=((u"\u203d", 1),)) == "%E2%80%BD=1"
|
||||
assert tmpl.render(o={u"\u203d": 1}) == "%E2%80%BD=1"
|
||||
assert tmpl.render(o={0: 1}) == "0=1"
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(FilterTestCase))
|
||||
return suite
|
@ -1,141 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.imports
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the import features (with includes).
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment, DictLoader
|
||||
from jinja2.exceptions import TemplateNotFound, TemplatesNotFound
|
||||
|
||||
|
||||
test_env = Environment(loader=DictLoader(dict(
|
||||
module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}',
|
||||
header='[{{ foo }}|{{ 23 }}]',
|
||||
o_printer='({{ o }})'
|
||||
)))
|
||||
test_env.globals['bar'] = 23
|
||||
|
||||
|
||||
class ImportsTestCase(JinjaTestCase):
|
||||
|
||||
def test_context_imports(self):
|
||||
t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
|
||||
assert t.render(foo=42) == '[|23]'
|
||||
t = test_env.from_string('{% import "module" as m without context %}{{ m.test() }}')
|
||||
assert t.render(foo=42) == '[|23]'
|
||||
t = test_env.from_string('{% import "module" as m with context %}{{ m.test() }}')
|
||||
assert t.render(foo=42) == '[42|23]'
|
||||
t = test_env.from_string('{% from "module" import test %}{{ test() }}')
|
||||
assert t.render(foo=42) == '[|23]'
|
||||
t = test_env.from_string('{% from "module" import test without context %}{{ test() }}')
|
||||
assert t.render(foo=42) == '[|23]'
|
||||
t = test_env.from_string('{% from "module" import test with context %}{{ test() }}')
|
||||
assert t.render(foo=42) == '[42|23]'
|
||||
|
||||
def test_trailing_comma(self):
|
||||
test_env.from_string('{% from "foo" import bar, baz with context %}')
|
||||
test_env.from_string('{% from "foo" import bar, baz, with context %}')
|
||||
test_env.from_string('{% from "foo" import bar, with context %}')
|
||||
test_env.from_string('{% from "foo" import bar, with, context %}')
|
||||
test_env.from_string('{% from "foo" import bar, with with context %}')
|
||||
|
||||
def test_exports(self):
|
||||
m = test_env.from_string('''
|
||||
{% macro toplevel() %}...{% endmacro %}
|
||||
{% macro __private() %}...{% endmacro %}
|
||||
{% set variable = 42 %}
|
||||
{% for item in [1] %}
|
||||
{% macro notthere() %}{% endmacro %}
|
||||
{% endfor %}
|
||||
''').module
|
||||
assert m.toplevel() == '...'
|
||||
assert not hasattr(m, '__missing')
|
||||
assert m.variable == 42
|
||||
assert not hasattr(m, 'notthere')
|
||||
|
||||
|
||||
class IncludesTestCase(JinjaTestCase):
|
||||
|
||||
def test_context_include(self):
|
||||
t = test_env.from_string('{% include "header" %}')
|
||||
assert t.render(foo=42) == '[42|23]'
|
||||
t = test_env.from_string('{% include "header" with context %}')
|
||||
assert t.render(foo=42) == '[42|23]'
|
||||
t = test_env.from_string('{% include "header" without context %}')
|
||||
assert t.render(foo=42) == '[|23]'
|
||||
|
||||
def test_choice_includes(self):
|
||||
t = test_env.from_string('{% include ["missing", "header"] %}')
|
||||
assert t.render(foo=42) == '[42|23]'
|
||||
|
||||
t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}')
|
||||
assert t.render(foo=42) == ''
|
||||
|
||||
t = test_env.from_string('{% include ["missing", "missing2"] %}')
|
||||
self.assert_raises(TemplateNotFound, t.render)
|
||||
try:
|
||||
t.render()
|
||||
except TemplatesNotFound, e:
|
||||
assert e.templates == ['missing', 'missing2']
|
||||
assert e.name == 'missing2'
|
||||
else:
|
||||
assert False, 'thou shalt raise'
|
||||
|
||||
def test_includes(t, **ctx):
|
||||
ctx['foo'] = 42
|
||||
assert t.render(ctx) == '[42|23]'
|
||||
|
||||
t = test_env.from_string('{% include ["missing", "header"] %}')
|
||||
test_includes(t)
|
||||
t = test_env.from_string('{% include x %}')
|
||||
test_includes(t, x=['missing', 'header'])
|
||||
t = test_env.from_string('{% include [x, "header"] %}')
|
||||
test_includes(t, x='missing')
|
||||
t = test_env.from_string('{% include x %}')
|
||||
test_includes(t, x='header')
|
||||
t = test_env.from_string('{% include x %}')
|
||||
test_includes(t, x='header')
|
||||
t = test_env.from_string('{% include [x] %}')
|
||||
test_includes(t, x='header')
|
||||
|
||||
def test_include_ignoring_missing(self):
|
||||
t = test_env.from_string('{% include "missing" %}')
|
||||
self.assert_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(self):
|
||||
env = Environment(loader=DictLoader(dict(
|
||||
main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
|
||||
item="{{ item }}"
|
||||
)))
|
||||
assert env.get_template("main").render() == "123"
|
||||
|
||||
def test_unoptimized_scopes(self):
|
||||
t = test_env.from_string("""
|
||||
{% macro outer(o) %}
|
||||
{% macro inner() %}
|
||||
{% include "o_printer" %}
|
||||
{% endmacro %}
|
||||
{{ inner() }}
|
||||
{% endmacro %}
|
||||
{{ outer("FOO") }}
|
||||
""")
|
||||
assert t.render().strip() == '(FOO)'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(ImportsTestCase))
|
||||
suite.addTest(unittest.makeSuite(IncludesTestCase))
|
||||
return suite
|
@ -1,227 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.inheritance
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests the template inheritance feature.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment, DictLoader
|
||||
|
||||
|
||||
LAYOUTTEMPLATE = '''\
|
||||
|{% block block1 %}block 1 from layout{% endblock %}
|
||||
|{% block block2 %}block 2 from layout{% endblock %}
|
||||
|{% block block3 %}
|
||||
{% block block4 %}nested block 4 from layout{% endblock %}
|
||||
{% endblock %}|'''
|
||||
|
||||
LEVEL1TEMPLATE = '''\
|
||||
{% extends "layout" %}
|
||||
{% block block1 %}block 1 from level1{% endblock %}'''
|
||||
|
||||
LEVEL2TEMPLATE = '''\
|
||||
{% extends "level1" %}
|
||||
{% block block2 %}{% block block5 %}nested block 5 from level2{%
|
||||
endblock %}{% endblock %}'''
|
||||
|
||||
LEVEL3TEMPLATE = '''\
|
||||
{% extends "level2" %}
|
||||
{% block block5 %}block 5 from level3{% endblock %}
|
||||
{% block block4 %}block 4 from level3{% endblock %}
|
||||
'''
|
||||
|
||||
LEVEL4TEMPLATE = '''\
|
||||
{% extends "level3" %}
|
||||
{% block block3 %}block 3 from level4{% endblock %}
|
||||
'''
|
||||
|
||||
WORKINGTEMPLATE = '''\
|
||||
{% extends "layout" %}
|
||||
{% block block1 %}
|
||||
{% if false %}
|
||||
{% block block2 %}
|
||||
this should workd
|
||||
{% endblock %}
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
'''
|
||||
|
||||
env = Environment(loader=DictLoader({
|
||||
'layout': LAYOUTTEMPLATE,
|
||||
'level1': LEVEL1TEMPLATE,
|
||||
'level2': LEVEL2TEMPLATE,
|
||||
'level3': LEVEL3TEMPLATE,
|
||||
'level4': LEVEL4TEMPLATE,
|
||||
'working': WORKINGTEMPLATE
|
||||
}), trim_blocks=True)
|
||||
|
||||
|
||||
class InheritanceTestCase(JinjaTestCase):
|
||||
|
||||
def test_layout(self):
|
||||
tmpl = env.get_template('layout')
|
||||
assert tmpl.render() == ('|block 1 from layout|block 2 from '
|
||||
'layout|nested block 4 from layout|')
|
||||
|
||||
def test_level1(self):
|
||||
tmpl = env.get_template('level1')
|
||||
assert tmpl.render() == ('|block 1 from level1|block 2 from '
|
||||
'layout|nested block 4 from layout|')
|
||||
|
||||
def test_level2(self):
|
||||
tmpl = env.get_template('level2')
|
||||
assert tmpl.render() == ('|block 1 from level1|nested block 5 from '
|
||||
'level2|nested block 4 from layout|')
|
||||
|
||||
def test_level3(self):
|
||||
tmpl = env.get_template('level3')
|
||||
assert tmpl.render() == ('|block 1 from level1|block 5 from level3|'
|
||||
'block 4 from level3|')
|
||||
|
||||
def test_level4(sel):
|
||||
tmpl = env.get_template('level4')
|
||||
assert tmpl.render() == ('|block 1 from level1|block 5 from '
|
||||
'level3|block 3 from level4|')
|
||||
|
||||
def test_super(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'a': '{% block intro %}INTRO{% endblock %}|'
|
||||
'BEFORE|{% block data %}INNER{% endblock %}|AFTER',
|
||||
'b': '{% extends "a" %}{% block data %}({{ '
|
||||
'super() }}){% endblock %}',
|
||||
'c': '{% extends "b" %}{% block intro %}--{{ '
|
||||
'super() }}--{% endblock %}\n{% block data '
|
||||
'%}[{{ super() }}]{% endblock %}'
|
||||
}))
|
||||
tmpl = env.get_template('c')
|
||||
assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER'
|
||||
|
||||
def test_working(self):
|
||||
tmpl = env.get_template('working')
|
||||
|
||||
def test_reuse_blocks(self):
|
||||
tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42'
|
||||
'{% endblock %}|{{ self.foo() }}')
|
||||
assert tmpl.render() == '42|42|42'
|
||||
|
||||
def test_preserve_blocks(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'a': '{% if false %}{% block x %}A{% endblock %}{% endif %}{{ self.x() }}',
|
||||
'b': '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}'
|
||||
}))
|
||||
tmpl = env.get_template('b')
|
||||
assert tmpl.render() == 'BA'
|
||||
|
||||
def test_dynamic_inheritance(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'master1': 'MASTER1{% block x %}{% endblock %}',
|
||||
'master2': 'MASTER2{% block x %}{% endblock %}',
|
||||
'child': '{% extends master %}{% block x %}CHILD{% endblock %}'
|
||||
}))
|
||||
tmpl = env.get_template('child')
|
||||
for m in range(1, 3):
|
||||
assert tmpl.render(master='master%d' % m) == 'MASTER%dCHILD' % m
|
||||
|
||||
def test_multi_inheritance(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'master1': 'MASTER1{% block x %}{% endblock %}',
|
||||
'master2': 'MASTER2{% block x %}{% endblock %}',
|
||||
'child': '''{% if master %}{% extends master %}{% else %}{% extends
|
||||
'master1' %}{% endif %}{% block x %}CHILD{% endblock %}'''
|
||||
}))
|
||||
tmpl = env.get_template('child')
|
||||
assert tmpl.render(master='master2') == 'MASTER2CHILD'
|
||||
assert tmpl.render(master='master1') == 'MASTER1CHILD'
|
||||
assert tmpl.render() == 'MASTER1CHILD'
|
||||
|
||||
def test_scoped_block(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'master.html': '{% for item in seq %}[{% block item scoped %}'
|
||||
'{% endblock %}]{% endfor %}'
|
||||
}))
|
||||
t = env.from_string('{% extends "master.html" %}{% block item %}'
|
||||
'{{ item }}{% endblock %}')
|
||||
assert t.render(seq=range(5)) == '[0][1][2][3][4]'
|
||||
|
||||
def test_super_in_scoped_block(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'master.html': '{% for item in seq %}[{% block item scoped %}'
|
||||
'{{ item }}{% endblock %}]{% endfor %}'
|
||||
}))
|
||||
t = env.from_string('{% extends "master.html" %}{% block item %}'
|
||||
'{{ super() }}|{{ item * 2 }}{% endblock %}')
|
||||
assert t.render(seq=range(5)) == '[0|0][1|2][2|4][3|6][4|8]'
|
||||
|
||||
def test_scoped_block_after_inheritance(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'layout.html': '''
|
||||
{% block useless %}{% endblock %}
|
||||
''',
|
||||
'index.html': '''
|
||||
{%- extends 'layout.html' %}
|
||||
{% from 'helpers.html' import foo with context %}
|
||||
{% block useless %}
|
||||
{% for x in [1, 2, 3] %}
|
||||
{% block testing scoped %}
|
||||
{{ foo(x) }}
|
||||
{% endblock %}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
||||
''',
|
||||
'helpers.html': '''
|
||||
{% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
|
||||
'''
|
||||
}))
|
||||
rv = env.get_template('index.html').render(the_foo=42).split()
|
||||
assert rv == ['43', '44', '45']
|
||||
|
||||
|
||||
class BugFixTestCase(JinjaTestCase):
|
||||
|
||||
def test_fixed_macro_scoping_bug(self):
|
||||
assert Environment(loader=DictLoader({
|
||||
'test.html': '''\
|
||||
{% extends 'details.html' %}
|
||||
|
||||
{% macro my_macro() %}
|
||||
my_macro
|
||||
{% endmacro %}
|
||||
|
||||
{% block inner_box %}
|
||||
{{ my_macro() }}
|
||||
{% endblock %}
|
||||
''',
|
||||
'details.html': '''\
|
||||
{% extends 'standard.html' %}
|
||||
|
||||
{% macro my_macro() %}
|
||||
my_macro
|
||||
{% endmacro %}
|
||||
|
||||
{% block content %}
|
||||
{% block outer_box %}
|
||||
outer_box
|
||||
{% block inner_box %}
|
||||
inner_box
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
''',
|
||||
'standard.html': '''
|
||||
{% block content %} {% endblock %}
|
||||
'''
|
||||
})).get_template("test.html").render().split() == [u'outer_box', u'my_macro']
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(InheritanceTestCase))
|
||||
suite.addTest(unittest.makeSuite(BugFixTestCase))
|
||||
return suite
|
@ -1,387 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.lexnparse
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
All the unittests regarding lexing, parsing and syntax.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment, Template, TemplateSyntaxError, \
|
||||
UndefinedError, nodes
|
||||
|
||||
env = Environment()
|
||||
|
||||
|
||||
# how does a string look like in jinja syntax?
|
||||
if sys.version_info < (3, 0):
|
||||
def jinja_string_repr(string):
|
||||
return repr(string)[1:]
|
||||
else:
|
||||
jinja_string_repr = repr
|
||||
|
||||
|
||||
class LexerTestCase(JinjaTestCase):
|
||||
|
||||
def test_raw1(self):
|
||||
tmpl = env.from_string('{% raw %}foo{% endraw %}|'
|
||||
'{%raw%}{{ bar }}|{% baz %}{% endraw %}')
|
||||
assert tmpl.render() == 'foo|{{ bar }}|{% baz %}'
|
||||
|
||||
def test_raw2(self):
|
||||
tmpl = env.from_string('1 {%- raw -%} 2 {%- endraw -%} 3')
|
||||
assert tmpl.render() == '123'
|
||||
|
||||
def test_balancing(self):
|
||||
env = Environment('{%', '%}', '${', '}')
|
||||
tmpl = env.from_string('''{% for item in seq
|
||||
%}${{'foo': item}|upper}{% endfor %}''')
|
||||
assert tmpl.render(seq=range(3)) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
|
||||
|
||||
def test_comments(self):
|
||||
env = Environment('<!--', '-->', '{', '}')
|
||||
tmpl = env.from_string('''\
|
||||
<ul>
|
||||
<!--- for item in seq -->
|
||||
<li>{item}</li>
|
||||
<!--- endfor -->
|
||||
</ul>''')
|
||||
assert tmpl.render(seq=range(3)) == ("<ul>\n <li>0</li>\n "
|
||||
"<li>1</li>\n <li>2</li>\n</ul>")
|
||||
|
||||
def test_string_escapes(self):
|
||||
for char in u'\0', u'\u2668', u'\xe4', u'\t', u'\r', u'\n':
|
||||
tmpl = env.from_string('{{ %s }}' % jinja_string_repr(char))
|
||||
assert tmpl.render() == char
|
||||
assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u'\u2668'
|
||||
|
||||
def test_bytefallback(self):
|
||||
from pprint import pformat
|
||||
tmpl = env.from_string(u'''{{ 'foo'|pprint }}|{{ 'bär'|pprint }}''')
|
||||
assert tmpl.render() == pformat('foo') + '|' + pformat(u'bär')
|
||||
|
||||
def test_operators(self):
|
||||
from jinja2.lexer import operators
|
||||
for test, expect in operators.iteritems():
|
||||
if test in '([{}])':
|
||||
continue
|
||||
stream = env.lexer.tokenize('{{ %s }}' % test)
|
||||
stream.next()
|
||||
assert stream.current.type == expect
|
||||
|
||||
def test_normalizing(self):
|
||||
for seq in '\r', '\r\n', '\n':
|
||||
env = Environment(newline_sequence=seq)
|
||||
tmpl = env.from_string('1\n2\r\n3\n4\n')
|
||||
result = tmpl.render()
|
||||
assert result.replace(seq, 'X') == '1X2X3X4'
|
||||
|
||||
|
||||
class ParserTestCase(JinjaTestCase):
|
||||
|
||||
def test_php_syntax(self):
|
||||
env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->')
|
||||
tmpl = env.from_string('''\
|
||||
<!-- I'm a comment, I'm not interesting -->\
|
||||
<? for item in seq -?>
|
||||
<?= item ?>
|
||||
<?- endfor ?>''')
|
||||
assert tmpl.render(seq=range(5)) == '01234'
|
||||
|
||||
def test_erb_syntax(self):
|
||||
env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>')
|
||||
tmpl = env.from_string('''\
|
||||
<%# I'm a comment, I'm not interesting %>\
|
||||
<% for item in seq -%>
|
||||
<%= item %>
|
||||
<%- endfor %>''')
|
||||
assert tmpl.render(seq=range(5)) == '01234'
|
||||
|
||||
def test_comment_syntax(self):
|
||||
env = Environment('<!--', '-->', '${', '}', '<!--#', '-->')
|
||||
tmpl = env.from_string('''\
|
||||
<!--# I'm a comment, I'm not interesting -->\
|
||||
<!-- for item in seq --->
|
||||
${item}
|
||||
<!--- endfor -->''')
|
||||
assert tmpl.render(seq=range(5)) == '01234'
|
||||
|
||||
def test_balancing(self):
|
||||
tmpl = env.from_string('''{{{'foo':'bar'}.foo}}''')
|
||||
assert tmpl.render() == 'bar'
|
||||
|
||||
def test_start_comment(self):
|
||||
tmpl = env.from_string('''{# foo comment
|
||||
and bar comment #}
|
||||
{% macro blub() %}foo{% endmacro %}
|
||||
{{ blub() }}''')
|
||||
assert tmpl.render().strip() == 'foo'
|
||||
|
||||
def test_line_syntax(self):
|
||||
env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%')
|
||||
tmpl = env.from_string('''\
|
||||
<%# regular comment %>
|
||||
% for item in seq:
|
||||
${item}
|
||||
% endfor''')
|
||||
assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \
|
||||
range(5)
|
||||
|
||||
env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##')
|
||||
tmpl = env.from_string('''\
|
||||
<%# regular comment %>
|
||||
% for item in seq:
|
||||
${item} ## the rest of the stuff
|
||||
% endfor''')
|
||||
assert [int(x.strip()) for x in tmpl.render(seq=range(5)).split()] == \
|
||||
range(5)
|
||||
|
||||
def test_line_syntax_priority(self):
|
||||
# XXX: why is the whitespace there in front of the newline?
|
||||
env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#')
|
||||
tmpl = env.from_string('''\
|
||||
/* ignore me.
|
||||
I'm a multiline comment */
|
||||
## for item in seq:
|
||||
* ${item} # this is just extra stuff
|
||||
## endfor''')
|
||||
assert tmpl.render(seq=[1, 2]).strip() == '* 1\n* 2'
|
||||
env = Environment('{%', '%}', '${', '}', '/*', '*/', '#', '##')
|
||||
tmpl = env.from_string('''\
|
||||
/* ignore me.
|
||||
I'm a multiline comment */
|
||||
# for item in seq:
|
||||
* ${item} ## this is just extra stuff
|
||||
## extra stuff i just want to ignore
|
||||
# endfor''')
|
||||
assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2'
|
||||
|
||||
def test_error_messages(self):
|
||||
def assert_error(code, expected):
|
||||
try:
|
||||
Template(code)
|
||||
except TemplateSyntaxError, e:
|
||||
assert str(e) == expected, 'unexpected error message'
|
||||
else:
|
||||
assert False, 'that was supposed to be an error'
|
||||
|
||||
assert_error('{% for item in seq %}...{% endif %}',
|
||||
"Encountered unknown tag 'endif'. Jinja was looking "
|
||||
"for the following tags: 'endfor' or 'else'. The "
|
||||
"innermost block that needs to be closed is 'for'.")
|
||||
assert_error('{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}',
|
||||
"Encountered unknown tag 'endfor'. Jinja was looking for "
|
||||
"the following tags: 'elif' or 'else' or 'endif'. The "
|
||||
"innermost block that needs to be closed is 'if'.")
|
||||
assert_error('{% if foo %}',
|
||||
"Unexpected end of template. Jinja was looking for the "
|
||||
"following tags: 'elif' or 'else' or 'endif'. The "
|
||||
"innermost block that needs to be closed is 'if'.")
|
||||
assert_error('{% for item in seq %}',
|
||||
"Unexpected end of template. Jinja was looking for the "
|
||||
"following tags: 'endfor' or 'else'. The innermost block "
|
||||
"that needs to be closed is 'for'.")
|
||||
assert_error('{% block foo-bar-baz %}',
|
||||
"Block names in Jinja have to be valid Python identifiers "
|
||||
"and may not contain hyphens, use an underscore instead.")
|
||||
assert_error('{% unknown_tag %}',
|
||||
"Encountered unknown tag 'unknown_tag'.")
|
||||
|
||||
|
||||
class SyntaxTestCase(JinjaTestCase):
|
||||
|
||||
def test_call(self):
|
||||
env = Environment()
|
||||
env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
|
||||
tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}")
|
||||
assert tmpl.render() == 'abdfh'
|
||||
|
||||
def test_slicing(self):
|
||||
tmpl = env.from_string('{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}')
|
||||
assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
|
||||
|
||||
def test_attr(self):
|
||||
tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
|
||||
assert tmpl.render(foo={'bar': 42}) == '42|42'
|
||||
|
||||
def test_subscript(self):
|
||||
tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
|
||||
assert tmpl.render(foo=[0, 1, 2]) == '0|2'
|
||||
|
||||
def test_tuple(self):
|
||||
tmpl = env.from_string('{{ () }}|{{ (1,) }}|{{ (1, 2) }}')
|
||||
assert tmpl.render() == '()|(1,)|(1, 2)'
|
||||
|
||||
def test_math(self):
|
||||
tmpl = env.from_string('{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}')
|
||||
assert tmpl.render() == '1.5|8'
|
||||
|
||||
def test_div(self):
|
||||
tmpl = env.from_string('{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}')
|
||||
assert tmpl.render() == '1|1.5|1'
|
||||
|
||||
def test_unary(self):
|
||||
tmpl = env.from_string('{{ +3 }}|{{ -3 }}')
|
||||
assert tmpl.render() == '3|-3'
|
||||
|
||||
def test_concat(self):
|
||||
tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
|
||||
assert tmpl.render() == '[1, 2]foo'
|
||||
|
||||
def test_compare(self):
|
||||
tmpl = env.from_string('{{ 1 > 0 }}|{{ 1 >= 1 }}|{{ 2 < 3 }}|'
|
||||
'{{ 2 == 2 }}|{{ 1 <= 1 }}')
|
||||
assert tmpl.render() == 'True|True|True|True|True'
|
||||
|
||||
def test_inop(self):
|
||||
tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}')
|
||||
assert tmpl.render() == 'True|False'
|
||||
|
||||
def test_literals(self):
|
||||
tmpl = env.from_string('{{ [] }}|{{ {} }}|{{ () }}')
|
||||
assert tmpl.render().lower() == '[]|{}|()'
|
||||
|
||||
def test_bool(self):
|
||||
tmpl = env.from_string('{{ true and false }}|{{ false '
|
||||
'or true }}|{{ not false }}')
|
||||
assert tmpl.render() == 'False|True|True'
|
||||
|
||||
def test_grouping(self):
|
||||
tmpl = env.from_string('{{ (true and false) or (false and true) and not false }}')
|
||||
assert tmpl.render() == 'False'
|
||||
|
||||
def test_django_attr(self):
|
||||
tmpl = env.from_string('{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}')
|
||||
assert tmpl.render() == '1|1'
|
||||
|
||||
def test_conditional_expression(self):
|
||||
tmpl = env.from_string('''{{ 0 if true else 1 }}''')
|
||||
assert tmpl.render() == '0'
|
||||
|
||||
def test_short_conditional_expression(self):
|
||||
tmpl = env.from_string('<{{ 1 if false }}>')
|
||||
assert tmpl.render() == '<>'
|
||||
|
||||
tmpl = env.from_string('<{{ (1 if false).bar }}>')
|
||||
self.assert_raises(UndefinedError, tmpl.render)
|
||||
|
||||
def test_filter_priority(self):
|
||||
tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
|
||||
assert tmpl.render() == 'FOOBAR'
|
||||
|
||||
def test_function_calls(self):
|
||||
tests = [
|
||||
(True, '*foo, bar'),
|
||||
(True, '*foo, *bar'),
|
||||
(True, '*foo, bar=42'),
|
||||
(True, '**foo, *bar'),
|
||||
(True, '**foo, bar'),
|
||||
(False, 'foo, bar'),
|
||||
(False, 'foo, bar=42'),
|
||||
(False, 'foo, bar=23, *args'),
|
||||
(False, 'a, b=c, *d, **e'),
|
||||
(False, '*foo, **bar')
|
||||
]
|
||||
for should_fail, sig in tests:
|
||||
if should_fail:
|
||||
self.assert_raises(TemplateSyntaxError,
|
||||
env.from_string, '{{ foo(%s) }}' % sig)
|
||||
else:
|
||||
env.from_string('foo(%s)' % sig)
|
||||
|
||||
def test_tuple_expr(self):
|
||||
for tmpl in [
|
||||
'{{ () }}',
|
||||
'{{ (1, 2) }}',
|
||||
'{{ (1, 2,) }}',
|
||||
'{{ 1, }}',
|
||||
'{{ 1, 2 }}',
|
||||
'{% for foo, bar in seq %}...{% endfor %}',
|
||||
'{% for x in foo, bar %}...{% endfor %}',
|
||||
'{% for x in foo, %}...{% endfor %}'
|
||||
]:
|
||||
assert env.from_string(tmpl)
|
||||
|
||||
def test_trailing_comma(self):
|
||||
tmpl = env.from_string('{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}')
|
||||
assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}'
|
||||
|
||||
def test_block_end_name(self):
|
||||
env.from_string('{% block foo %}...{% endblock foo %}')
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||||
'{% block x %}{% endblock y %}')
|
||||
|
||||
def test_constant_casing(self):
|
||||
for const in True, False, None:
|
||||
tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % (
|
||||
str(const), str(const).lower(), str(const).upper()
|
||||
))
|
||||
assert tmpl.render() == '%s|%s|' % (const, const)
|
||||
|
||||
def test_test_chaining(self):
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||||
'{{ foo is string is sequence }}')
|
||||
assert env.from_string('{{ 42 is string or 42 is number }}'
|
||||
).render() == 'True'
|
||||
|
||||
def test_string_concatenation(self):
|
||||
tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
|
||||
assert tmpl.render() == 'foobarbaz'
|
||||
|
||||
def test_notin(self):
|
||||
bar = xrange(100)
|
||||
tmpl = env.from_string('''{{ not 42 in bar }}''')
|
||||
assert tmpl.render(bar=bar) == unicode(not 42 in bar)
|
||||
|
||||
def test_implicit_subscribed_tuple(self):
|
||||
class Foo(object):
|
||||
def __getitem__(self, x):
|
||||
return x
|
||||
t = env.from_string('{{ foo[1, 2] }}')
|
||||
assert t.render(foo=Foo()) == u'(1, 2)'
|
||||
|
||||
def test_raw2(self):
|
||||
tmpl = env.from_string('{% raw %}{{ FOO }} and {% BAR %}{% endraw %}')
|
||||
assert tmpl.render() == '{{ FOO }} and {% BAR %}'
|
||||
|
||||
def test_const(self):
|
||||
tmpl = env.from_string('{{ true }}|{{ false }}|{{ none }}|'
|
||||
'{{ none is defined }}|{{ missing is defined }}')
|
||||
assert tmpl.render() == 'True|False|None|True|False'
|
||||
|
||||
def test_neg_filter_priority(self):
|
||||
node = env.parse('{{ -1|foo }}')
|
||||
assert isinstance(node.body[0].nodes[0], nodes.Filter)
|
||||
assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
|
||||
|
||||
def test_const_assign(self):
|
||||
constass1 = '''{% set true = 42 %}'''
|
||||
constass2 = '''{% for none in seq %}{% endfor %}'''
|
||||
for tmpl in constass1, constass2:
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string, tmpl)
|
||||
|
||||
def test_localset(self):
|
||||
tmpl = env.from_string('''{% set foo = 0 %}\
|
||||
{% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
|
||||
{{ foo }}''')
|
||||
assert tmpl.render() == '0'
|
||||
|
||||
def test_parse_unary(self):
|
||||
tmpl = env.from_string('{{ -foo["bar"] }}')
|
||||
assert tmpl.render(foo={'bar': 42}) == '-42'
|
||||
tmpl = env.from_string('{{ -foo["bar"]|abs }}')
|
||||
assert tmpl.render(foo={'bar': 42}) == '42'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(LexerTestCase))
|
||||
suite.addTest(unittest.makeSuite(ParserTestCase))
|
||||
suite.addTest(unittest.makeSuite(SyntaxTestCase))
|
||||
return suite
|
@ -1,218 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.loader
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Test the loaders.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import tempfile
|
||||
import shutil
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase, dict_loader, \
|
||||
package_loader, filesystem_loader, function_loader, \
|
||||
choice_loader, prefix_loader
|
||||
|
||||
from jinja2 import Environment, loaders
|
||||
from jinja2.loaders import split_template_path
|
||||
from jinja2.exceptions import TemplateNotFound
|
||||
|
||||
|
||||
class LoaderTestCase(JinjaTestCase):
|
||||
|
||||
def test_dict_loader(self):
|
||||
env = Environment(loader=dict_loader)
|
||||
tmpl = env.get_template('justdict.html')
|
||||
assert tmpl.render().strip() == 'FOO'
|
||||
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
|
||||
|
||||
def test_package_loader(self):
|
||||
env = Environment(loader=package_loader)
|
||||
tmpl = env.get_template('test.html')
|
||||
assert tmpl.render().strip() == 'BAR'
|
||||
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
|
||||
|
||||
def test_filesystem_loader(self):
|
||||
env = Environment(loader=filesystem_loader)
|
||||
tmpl = env.get_template('test.html')
|
||||
assert tmpl.render().strip() == 'BAR'
|
||||
tmpl = env.get_template('foo/test.html')
|
||||
assert tmpl.render().strip() == 'FOO'
|
||||
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
|
||||
|
||||
def test_choice_loader(self):
|
||||
env = Environment(loader=choice_loader)
|
||||
tmpl = env.get_template('justdict.html')
|
||||
assert tmpl.render().strip() == 'FOO'
|
||||
tmpl = env.get_template('test.html')
|
||||
assert tmpl.render().strip() == 'BAR'
|
||||
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
|
||||
|
||||
def test_function_loader(self):
|
||||
env = Environment(loader=function_loader)
|
||||
tmpl = env.get_template('justfunction.html')
|
||||
assert tmpl.render().strip() == 'FOO'
|
||||
self.assert_raises(TemplateNotFound, env.get_template, 'missing.html')
|
||||
|
||||
def test_prefix_loader(self):
|
||||
env = Environment(loader=prefix_loader)
|
||||
tmpl = env.get_template('a/test.html')
|
||||
assert tmpl.render().strip() == 'BAR'
|
||||
tmpl = env.get_template('b/justdict.html')
|
||||
assert tmpl.render().strip() == 'FOO'
|
||||
self.assert_raises(TemplateNotFound, env.get_template, 'missing')
|
||||
|
||||
def test_caching(self):
|
||||
changed = False
|
||||
class TestLoader(loaders.BaseLoader):
|
||||
def get_source(self, environment, template):
|
||||
return u'foo', None, lambda: not changed
|
||||
env = Environment(loader=TestLoader(), cache_size=-1)
|
||||
tmpl = env.get_template('template')
|
||||
assert tmpl is env.get_template('template')
|
||||
changed = True
|
||||
assert tmpl is not env.get_template('template')
|
||||
changed = False
|
||||
|
||||
env = Environment(loader=TestLoader(), cache_size=0)
|
||||
assert env.get_template('template') \
|
||||
is not env.get_template('template')
|
||||
|
||||
env = Environment(loader=TestLoader(), cache_size=2)
|
||||
t1 = env.get_template('one')
|
||||
t2 = env.get_template('two')
|
||||
assert t2 is env.get_template('two')
|
||||
assert t1 is env.get_template('one')
|
||||
t3 = env.get_template('three')
|
||||
assert 'one' in env.cache
|
||||
assert 'two' not in env.cache
|
||||
assert 'three' in env.cache
|
||||
|
||||
def test_split_template_path(self):
|
||||
assert split_template_path('foo/bar') == ['foo', 'bar']
|
||||
assert split_template_path('./foo/bar') == ['foo', 'bar']
|
||||
self.assert_raises(TemplateNotFound, split_template_path, '../foo')
|
||||
|
||||
|
||||
class ModuleLoaderTestCase(JinjaTestCase):
|
||||
archive = None
|
||||
|
||||
def compile_down(self, zip='deflated', py_compile=False):
|
||||
super(ModuleLoaderTestCase, self).setup()
|
||||
log = []
|
||||
self.reg_env = Environment(loader=prefix_loader)
|
||||
if zip is not None:
|
||||
self.archive = tempfile.mkstemp(suffix='.zip')[1]
|
||||
else:
|
||||
self.archive = tempfile.mkdtemp()
|
||||
self.reg_env.compile_templates(self.archive, zip=zip,
|
||||
log_function=log.append,
|
||||
py_compile=py_compile)
|
||||
self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
|
||||
return ''.join(log)
|
||||
|
||||
def teardown(self):
|
||||
super(ModuleLoaderTestCase, self).teardown()
|
||||
if hasattr(self, 'mod_env'):
|
||||
if os.path.isfile(self.archive):
|
||||
os.remove(self.archive)
|
||||
else:
|
||||
shutil.rmtree(self.archive)
|
||||
self.archive = None
|
||||
|
||||
def test_log(self):
|
||||
log = self.compile_down()
|
||||
assert 'Compiled "a/foo/test.html" as ' \
|
||||
'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log
|
||||
assert 'Finished compiling templates' in log
|
||||
assert 'Could not compile "a/syntaxerror.html": ' \
|
||||
'Encountered unknown tag \'endif\'' in log
|
||||
|
||||
def _test_common(self):
|
||||
tmpl1 = self.reg_env.get_template('a/test.html')
|
||||
tmpl2 = self.mod_env.get_template('a/test.html')
|
||||
assert tmpl1.render() == tmpl2.render()
|
||||
|
||||
tmpl1 = self.reg_env.get_template('b/justdict.html')
|
||||
tmpl2 = self.mod_env.get_template('b/justdict.html')
|
||||
assert tmpl1.render() == tmpl2.render()
|
||||
|
||||
def test_deflated_zip_compile(self):
|
||||
self.compile_down(zip='deflated')
|
||||
self._test_common()
|
||||
|
||||
def test_stored_zip_compile(self):
|
||||
self.compile_down(zip='stored')
|
||||
self._test_common()
|
||||
|
||||
def test_filesystem_compile(self):
|
||||
self.compile_down(zip=None)
|
||||
self._test_common()
|
||||
|
||||
def test_weak_references(self):
|
||||
self.compile_down()
|
||||
tmpl = self.mod_env.get_template('a/test.html')
|
||||
key = loaders.ModuleLoader.get_template_key('a/test.html')
|
||||
name = self.mod_env.loader.module.__name__
|
||||
|
||||
assert hasattr(self.mod_env.loader.module, key)
|
||||
assert name in sys.modules
|
||||
|
||||
# unset all, ensure the module is gone from sys.modules
|
||||
self.mod_env = tmpl = None
|
||||
|
||||
try:
|
||||
import gc
|
||||
gc.collect()
|
||||
except:
|
||||
pass
|
||||
|
||||
assert name not in sys.modules
|
||||
|
||||
def test_byte_compilation(self):
|
||||
log = self.compile_down(py_compile=True)
|
||||
assert 'Byte-compiled "a/test.html"' in log
|
||||
tmpl1 = self.mod_env.get_template('a/test.html')
|
||||
mod = self.mod_env.loader.module. \
|
||||
tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
|
||||
assert mod.__file__.endswith('.pyc')
|
||||
|
||||
def test_choice_loader(self):
|
||||
log = self.compile_down(py_compile=True)
|
||||
assert 'Byte-compiled "a/test.html"' in log
|
||||
|
||||
self.mod_env.loader = loaders.ChoiceLoader([
|
||||
self.mod_env.loader,
|
||||
loaders.DictLoader({'DICT_SOURCE': 'DICT_TEMPLATE'})
|
||||
])
|
||||
|
||||
tmpl1 = self.mod_env.get_template('a/test.html')
|
||||
self.assert_equal(tmpl1.render(), 'BAR')
|
||||
tmpl2 = self.mod_env.get_template('DICT_SOURCE')
|
||||
self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE')
|
||||
|
||||
def test_prefix_loader(self):
|
||||
log = self.compile_down(py_compile=True)
|
||||
assert 'Byte-compiled "a/test.html"' in log
|
||||
|
||||
self.mod_env.loader = loaders.PrefixLoader({
|
||||
'MOD': self.mod_env.loader,
|
||||
'DICT': loaders.DictLoader({'test.html': 'DICT_TEMPLATE'})
|
||||
})
|
||||
|
||||
tmpl1 = self.mod_env.get_template('MOD/a/test.html')
|
||||
self.assert_equal(tmpl1.render(), 'BAR')
|
||||
tmpl2 = self.mod_env.get_template('DICT/test.html')
|
||||
self.assert_equal(tmpl2.render(), 'DICT_TEMPLATE')
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(LoaderTestCase))
|
||||
suite.addTest(unittest.makeSuite(ModuleLoaderTestCase))
|
||||
return suite
|
@ -1,255 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.regression
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests corner cases and bugs.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Template, Environment, DictLoader, TemplateSyntaxError, \
|
||||
TemplateNotFound, PrefixLoader
|
||||
|
||||
env = Environment()
|
||||
|
||||
|
||||
class CornerTestCase(JinjaTestCase):
|
||||
|
||||
def test_assigned_scoping(self):
|
||||
t = env.from_string('''
|
||||
{%- for item in (1, 2, 3, 4) -%}
|
||||
[{{ item }}]
|
||||
{%- endfor %}
|
||||
{{- item -}}
|
||||
''')
|
||||
assert t.render(item=42) == '[1][2][3][4]42'
|
||||
|
||||
t = env.from_string('''
|
||||
{%- for item in (1, 2, 3, 4) -%}
|
||||
[{{ item }}]
|
||||
{%- endfor %}
|
||||
{%- set item = 42 %}
|
||||
{{- item -}}
|
||||
''')
|
||||
assert t.render() == '[1][2][3][4]42'
|
||||
|
||||
t = env.from_string('''
|
||||
{%- set item = 42 %}
|
||||
{%- for item in (1, 2, 3, 4) -%}
|
||||
[{{ item }}]
|
||||
{%- endfor %}
|
||||
{{- item -}}
|
||||
''')
|
||||
assert t.render() == '[1][2][3][4]42'
|
||||
|
||||
def test_closure_scoping(self):
|
||||
t = env.from_string('''
|
||||
{%- set wrapper = "<FOO>" %}
|
||||
{%- for item in (1, 2, 3, 4) %}
|
||||
{%- macro wrapper() %}[{{ item }}]{% endmacro %}
|
||||
{{- wrapper() }}
|
||||
{%- endfor %}
|
||||
{{- wrapper -}}
|
||||
''')
|
||||
assert t.render() == '[1][2][3][4]<FOO>'
|
||||
|
||||
t = env.from_string('''
|
||||
{%- for item in (1, 2, 3, 4) %}
|
||||
{%- macro wrapper() %}[{{ item }}]{% endmacro %}
|
||||
{{- wrapper() }}
|
||||
{%- endfor %}
|
||||
{%- set wrapper = "<FOO>" %}
|
||||
{{- wrapper -}}
|
||||
''')
|
||||
assert t.render() == '[1][2][3][4]<FOO>'
|
||||
|
||||
t = env.from_string('''
|
||||
{%- for item in (1, 2, 3, 4) %}
|
||||
{%- macro wrapper() %}[{{ item }}]{% endmacro %}
|
||||
{{- wrapper() }}
|
||||
{%- endfor %}
|
||||
{{- wrapper -}}
|
||||
''')
|
||||
assert t.render(wrapper=23) == '[1][2][3][4]23'
|
||||
|
||||
|
||||
class BugTestCase(JinjaTestCase):
|
||||
|
||||
def test_keyword_folding(self):
|
||||
env = Environment()
|
||||
env.filters['testing'] = lambda value, some: value + some
|
||||
assert env.from_string("{{ 'test'|testing(some='stuff') }}") \
|
||||
.render() == 'teststuff'
|
||||
|
||||
def test_extends_output_bugs(self):
|
||||
env = Environment(loader=DictLoader({
|
||||
'parent.html': '(({% block title %}{% endblock %}))'
|
||||
}))
|
||||
|
||||
t = env.from_string('{% if expr %}{% extends "parent.html" %}{% endif %}'
|
||||
'[[{% block title %}title{% endblock %}]]'
|
||||
'{% for item in [1, 2, 3] %}({{ item }}){% endfor %}')
|
||||
assert t.render(expr=False) == '[[title]](1)(2)(3)'
|
||||
assert t.render(expr=True) == '((title))'
|
||||
|
||||
def test_urlize_filter_escaping(self):
|
||||
tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
|
||||
assert tmpl.render() == '<a href="http://www.example.org/<foo">http://www.example.org/<foo</a>'
|
||||
|
||||
def test_loop_call_loop(self):
|
||||
tmpl = env.from_string('''
|
||||
|
||||
{% macro test() %}
|
||||
{{ caller() }}
|
||||
{% endmacro %}
|
||||
|
||||
{% for num1 in range(5) %}
|
||||
{% call test() %}
|
||||
{% for num2 in range(10) %}
|
||||
{{ loop.index }}
|
||||
{% endfor %}
|
||||
{% endcall %}
|
||||
{% endfor %}
|
||||
|
||||
''')
|
||||
|
||||
assert tmpl.render().split() == map(unicode, range(1, 11)) * 5
|
||||
|
||||
def test_weird_inline_comment(self):
|
||||
env = Environment(line_statement_prefix='%')
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||||
'% for item in seq {# missing #}\n...% endfor')
|
||||
|
||||
def test_old_macro_loop_scoping_bug(self):
|
||||
tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}'
|
||||
'{% macro i() %}3{% endmacro %}{{ i() }}')
|
||||
assert tmpl.render() == '123'
|
||||
|
||||
def test_partial_conditional_assignments(self):
|
||||
tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}')
|
||||
assert tmpl.render(a=23) == '23'
|
||||
assert tmpl.render(b=True) == '42'
|
||||
|
||||
def test_stacked_locals_scoping_bug(self):
|
||||
env = Environment(line_statement_prefix='#')
|
||||
t = env.from_string('''\
|
||||
# for j in [1, 2]:
|
||||
# set x = 1
|
||||
# for i in [1, 2]:
|
||||
# print x
|
||||
# if i % 2 == 0:
|
||||
# set x = x + 1
|
||||
# endif
|
||||
# endfor
|
||||
# endfor
|
||||
# if a
|
||||
# print 'A'
|
||||
# elif b
|
||||
# print 'B'
|
||||
# elif c == d
|
||||
# print 'C'
|
||||
# else
|
||||
# print 'D'
|
||||
# endif
|
||||
''')
|
||||
assert t.render(a=0, b=False, c=42, d=42.0) == '1111C'
|
||||
|
||||
def test_stacked_locals_scoping_bug_twoframe(self):
|
||||
t = Template('''
|
||||
{% set x = 1 %}
|
||||
{% for item in foo %}
|
||||
{% if item == 1 %}
|
||||
{% set x = 2 %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{{ x }}
|
||||
''')
|
||||
rv = t.render(foo=[1]).strip()
|
||||
assert rv == u'1'
|
||||
|
||||
def test_call_with_args(self):
|
||||
t = Template("""{% macro dump_users(users) -%}
|
||||
<ul>
|
||||
{%- for user in users -%}
|
||||
<li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
|
||||
{%- endfor -%}
|
||||
</ul>
|
||||
{%- endmacro -%}
|
||||
|
||||
{% call(user) dump_users(list_of_user) -%}
|
||||
<dl>
|
||||
<dl>Realname</dl>
|
||||
<dd>{{ user.realname|e }}</dd>
|
||||
<dl>Description</dl>
|
||||
<dd>{{ user.description }}</dd>
|
||||
</dl>
|
||||
{% endcall %}""")
|
||||
|
||||
assert [x.strip() for x in t.render(list_of_user=[{
|
||||
'username':'apo',
|
||||
'realname':'something else',
|
||||
'description':'test'
|
||||
}]).splitlines()] == [
|
||||
u'<ul><li><p>apo</p><dl>',
|
||||
u'<dl>Realname</dl>',
|
||||
u'<dd>something else</dd>',
|
||||
u'<dl>Description</dl>',
|
||||
u'<dd>test</dd>',
|
||||
u'</dl>',
|
||||
u'</li></ul>'
|
||||
]
|
||||
|
||||
def test_empty_if_condition_fails(self):
|
||||
self.assert_raises(TemplateSyntaxError, Template, '{% if %}....{% endif %}')
|
||||
self.assert_raises(TemplateSyntaxError, Template, '{% if foo %}...{% elif %}...{% endif %}')
|
||||
self.assert_raises(TemplateSyntaxError, Template, '{% for x in %}..{% endfor %}')
|
||||
|
||||
def test_recursive_loop_bug(self):
|
||||
tpl1 = Template("""
|
||||
{% for p in foo recursive%}
|
||||
{{p.bar}}
|
||||
{% for f in p.fields recursive%}
|
||||
{{f.baz}}
|
||||
{{p.bar}}
|
||||
{% if f.rec %}
|
||||
{{ loop(f.sub) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
""")
|
||||
|
||||
tpl2 = Template("""
|
||||
{% for p in foo%}
|
||||
{{p.bar}}
|
||||
{% for f in p.fields recursive%}
|
||||
{{f.baz}}
|
||||
{{p.bar}}
|
||||
{% if f.rec %}
|
||||
{{ loop(f.sub) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
""")
|
||||
|
||||
def test_correct_prefix_loader_name(self):
|
||||
env = Environment(loader=PrefixLoader({
|
||||
'foo': DictLoader({})
|
||||
}))
|
||||
try:
|
||||
env.get_template('foo/bar.html')
|
||||
except TemplateNotFound, e:
|
||||
assert e.name == 'foo/bar.html'
|
||||
else:
|
||||
assert False, 'expected error here'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(CornerTestCase))
|
||||
suite.addTest(unittest.makeSuite(BugTestCase))
|
||||
return suite
|
@ -1,3 +0,0 @@
|
||||
Before
|
||||
{{ fail() }}
|
||||
After
|
@ -1 +0,0 @@
|
||||
FOO
|
@ -1,4 +0,0 @@
|
||||
Foo
|
||||
{% for item in broken %}
|
||||
...
|
||||
{% endif %}
|
@ -1 +0,0 @@
|
||||
BAR
|
@ -1,165 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.security
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Checks the sandbox and other security features.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Environment
|
||||
from jinja2.sandbox import SandboxedEnvironment, \
|
||||
ImmutableSandboxedEnvironment, unsafe
|
||||
from jinja2 import Markup, escape
|
||||
from jinja2.exceptions import SecurityError, TemplateSyntaxError, \
|
||||
TemplateRuntimeError
|
||||
|
||||
|
||||
class PrivateStuff(object):
|
||||
|
||||
def bar(self):
|
||||
return 23
|
||||
|
||||
@unsafe
|
||||
def foo(self):
|
||||
return 42
|
||||
|
||||
def __repr__(self):
|
||||
return 'PrivateStuff'
|
||||
|
||||
|
||||
class PublicStuff(object):
|
||||
bar = lambda self: 23
|
||||
_foo = lambda self: 42
|
||||
|
||||
def __repr__(self):
|
||||
return 'PublicStuff'
|
||||
|
||||
|
||||
class SandboxTestCase(JinjaTestCase):
|
||||
|
||||
def test_unsafe(self):
|
||||
env = SandboxedEnvironment()
|
||||
self.assert_raises(SecurityError, env.from_string("{{ foo.foo() }}").render,
|
||||
foo=PrivateStuff())
|
||||
self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()), '23')
|
||||
|
||||
self.assert_raises(SecurityError, env.from_string("{{ foo._foo() }}").render,
|
||||
foo=PublicStuff())
|
||||
self.assert_equal(env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()), '23')
|
||||
self.assert_equal(env.from_string("{{ foo.__class__ }}").render(foo=42), '')
|
||||
self.assert_equal(env.from_string("{{ foo.func_code }}").render(foo=lambda:None), '')
|
||||
# security error comes from __class__ already.
|
||||
self.assert_raises(SecurityError, env.from_string(
|
||||
"{{ foo.__class__.__subclasses__() }}").render, foo=42)
|
||||
|
||||
def test_immutable_environment(self):
|
||||
env = ImmutableSandboxedEnvironment()
|
||||
self.assert_raises(SecurityError, env.from_string(
|
||||
'{{ [].append(23) }}').render)
|
||||
self.assert_raises(SecurityError, env.from_string(
|
||||
'{{ {1:2}.clear() }}').render)
|
||||
|
||||
def test_restricted(self):
|
||||
env = SandboxedEnvironment()
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||||
"{% for item.attribute in seq %}...{% endfor %}")
|
||||
self.assert_raises(TemplateSyntaxError, env.from_string,
|
||||
"{% for foo, bar.baz in seq %}...{% endfor %}")
|
||||
|
||||
def test_markup_operations(self):
|
||||
# adding two strings should escape the unsafe one
|
||||
unsafe = '<script type="application/x-some-script">alert("foo");</script>'
|
||||
safe = Markup('<em>username</em>')
|
||||
assert unsafe + safe == unicode(escape(unsafe)) + unicode(safe)
|
||||
|
||||
# string interpolations are safe to use too
|
||||
assert Markup('<em>%s</em>') % '<bad user>' == \
|
||||
'<em><bad user></em>'
|
||||
assert Markup('<em>%(username)s</em>') % {
|
||||
'username': '<bad user>'
|
||||
} == '<em><bad user></em>'
|
||||
|
||||
# an escaped object is markup too
|
||||
assert type(Markup('foo') + 'bar') is Markup
|
||||
|
||||
# and it implements __html__ by returning itself
|
||||
x = Markup("foo")
|
||||
assert x.__html__() is x
|
||||
|
||||
# it also knows how to treat __html__ objects
|
||||
class Foo(object):
|
||||
def __html__(self):
|
||||
return '<em>awesome</em>'
|
||||
def __unicode__(self):
|
||||
return 'awesome'
|
||||
assert Markup(Foo()) == '<em>awesome</em>'
|
||||
assert Markup('<strong>%s</strong>') % Foo() == \
|
||||
'<strong><em>awesome</em></strong>'
|
||||
|
||||
# escaping and unescaping
|
||||
assert escape('"<>&\'') == '"<>&''
|
||||
assert Markup("<em>Foo & Bar</em>").striptags() == "Foo & Bar"
|
||||
assert Markup("<test>").unescape() == "<test>"
|
||||
|
||||
def test_template_data(self):
|
||||
env = Environment(autoescape=True)
|
||||
t = env.from_string('{% macro say_hello(name) %}'
|
||||
'<p>Hello {{ name }}!</p>{% endmacro %}'
|
||||
'{{ say_hello("<blink>foo</blink>") }}')
|
||||
escaped_out = '<p>Hello <blink>foo</blink>!</p>'
|
||||
assert t.render() == escaped_out
|
||||
assert unicode(t.module) == escaped_out
|
||||
assert escape(t.module) == escaped_out
|
||||
assert t.module.say_hello('<blink>foo</blink>') == escaped_out
|
||||
assert escape(t.module.say_hello('<blink>foo</blink>')) == escaped_out
|
||||
|
||||
def test_attr_filter(self):
|
||||
env = SandboxedEnvironment()
|
||||
tmpl = env.from_string('{{ cls|attr("__subclasses__")() }}')
|
||||
self.assert_raises(SecurityError, tmpl.render, cls=int)
|
||||
|
||||
def test_binary_operator_intercepting(self):
|
||||
def disable_op(left, right):
|
||||
raise TemplateRuntimeError('that operator so does not work')
|
||||
for expr, ctx, rv in ('1 + 2', {}, '3'), ('a + 2', {'a': 2}, '4'):
|
||||
env = SandboxedEnvironment()
|
||||
env.binop_table['+'] = disable_op
|
||||
t = env.from_string('{{ %s }}' % expr)
|
||||
assert t.render(ctx) == rv
|
||||
env.intercepted_binops = frozenset(['+'])
|
||||
t = env.from_string('{{ %s }}' % expr)
|
||||
try:
|
||||
t.render(ctx)
|
||||
except TemplateRuntimeError, e:
|
||||
pass
|
||||
else:
|
||||
self.fail('expected runtime error')
|
||||
|
||||
def test_unary_operator_intercepting(self):
|
||||
def disable_op(arg):
|
||||
raise TemplateRuntimeError('that operator so does not work')
|
||||
for expr, ctx, rv in ('-1', {}, '-1'), ('-a', {'a': 2}, '-2'):
|
||||
env = SandboxedEnvironment()
|
||||
env.unop_table['-'] = disable_op
|
||||
t = env.from_string('{{ %s }}' % expr)
|
||||
assert t.render(ctx) == rv
|
||||
env.intercepted_unops = frozenset(['-'])
|
||||
t = env.from_string('{{ %s }}' % expr)
|
||||
try:
|
||||
t.render(ctx)
|
||||
except TemplateRuntimeError, e:
|
||||
pass
|
||||
else:
|
||||
self.fail('expected runtime error')
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(SandboxTestCase))
|
||||
return suite
|
@ -1,93 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.tests
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Who tests the tests?
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import unittest
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2 import Markup, Environment
|
||||
|
||||
env = Environment()
|
||||
|
||||
|
||||
class TestsTestCase(JinjaTestCase):
|
||||
|
||||
def test_defined(self):
|
||||
tmpl = env.from_string('{{ missing is defined }}|{{ true is defined }}')
|
||||
assert tmpl.render() == 'False|True'
|
||||
|
||||
def test_even(self):
|
||||
tmpl = env.from_string('''{{ 1 is even }}|{{ 2 is even }}''')
|
||||
assert tmpl.render() == 'False|True'
|
||||
|
||||
def test_odd(self):
|
||||
tmpl = env.from_string('''{{ 1 is odd }}|{{ 2 is odd }}''')
|
||||
assert tmpl.render() == 'True|False'
|
||||
|
||||
def test_lower(self):
|
||||
tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''')
|
||||
assert tmpl.render() == 'True|False'
|
||||
|
||||
def test_typechecks(self):
|
||||
tmpl = env.from_string('''
|
||||
{{ 42 is undefined }}
|
||||
{{ 42 is defined }}
|
||||
{{ 42 is none }}
|
||||
{{ none is none }}
|
||||
{{ 42 is number }}
|
||||
{{ 42 is string }}
|
||||
{{ "foo" is string }}
|
||||
{{ "foo" is sequence }}
|
||||
{{ [1] is sequence }}
|
||||
{{ range is callable }}
|
||||
{{ 42 is callable }}
|
||||
{{ range(5) is iterable }}
|
||||
{{ {} is mapping }}
|
||||
{{ mydict is mapping }}
|
||||
{{ [] is mapping }}
|
||||
''')
|
||||
class MyDict(dict):
|
||||
pass
|
||||
assert tmpl.render(mydict=MyDict()).split() == [
|
||||
'False', 'True', 'False', 'True', 'True', 'False',
|
||||
'True', 'True', 'True', 'True', 'False', 'True',
|
||||
'True', 'True', 'False'
|
||||
]
|
||||
|
||||
def test_sequence(self):
|
||||
tmpl = env.from_string(
|
||||
'{{ [1, 2, 3] is sequence }}|'
|
||||
'{{ "foo" is sequence }}|'
|
||||
'{{ 42 is sequence }}'
|
||||
)
|
||||
assert tmpl.render() == 'True|True|False'
|
||||
|
||||
def test_upper(self):
|
||||
tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
|
||||
assert tmpl.render() == 'True|False'
|
||||
|
||||
def test_sameas(self):
|
||||
tmpl = env.from_string('{{ foo is sameas false }}|'
|
||||
'{{ 0 is sameas false }}')
|
||||
assert tmpl.render(foo=False) == 'True|False'
|
||||
|
||||
def test_no_paren_for_arg1(self):
|
||||
tmpl = env.from_string('{{ foo is sameas none }}')
|
||||
assert tmpl.render(foo=None) == 'True'
|
||||
|
||||
def test_escaped(self):
|
||||
env = Environment(autoescape=True)
|
||||
tmpl = env.from_string('{{ x is escaped }}|{{ y is escaped }}')
|
||||
assert tmpl.render(x='foo', y=Markup('foo')) == 'False|True'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(TestsTestCase))
|
||||
return suite
|
@ -1,82 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
jinja2.testsuite.utils
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Tests utilities jinja uses.
|
||||
|
||||
:copyright: (c) 2010 by the Jinja Team.
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import gc
|
||||
import unittest
|
||||
|
||||
import pickle
|
||||
|
||||
from jinja2.testsuite import JinjaTestCase
|
||||
|
||||
from jinja2.utils import LRUCache, escape, object_type_repr
|
||||
|
||||
|
||||
class LRUCacheTestCase(JinjaTestCase):
|
||||
|
||||
def test_simple(self):
|
||||
d = LRUCache(3)
|
||||
d["a"] = 1
|
||||
d["b"] = 2
|
||||
d["c"] = 3
|
||||
d["a"]
|
||||
d["d"] = 4
|
||||
assert len(d) == 3
|
||||
assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d
|
||||
|
||||
def test_pickleable(self):
|
||||
cache = LRUCache(2)
|
||||
cache["foo"] = 42
|
||||
cache["bar"] = 23
|
||||
cache["foo"]
|
||||
|
||||
for protocol in range(3):
|
||||
copy = pickle.loads(pickle.dumps(cache, protocol))
|
||||
assert copy.capacity == cache.capacity
|
||||
assert copy._mapping == cache._mapping
|
||||
assert copy._queue == cache._queue
|
||||
|
||||
|
||||
class HelpersTestCase(JinjaTestCase):
|
||||
|
||||
def test_object_type_repr(self):
|
||||
class X(object):
|
||||
pass
|
||||
self.assert_equal(object_type_repr(42), 'int object')
|
||||
self.assert_equal(object_type_repr([]), 'list object')
|
||||
self.assert_equal(object_type_repr(X()),
|
||||
'jinja2.testsuite.utils.X object')
|
||||
self.assert_equal(object_type_repr(None), 'None')
|
||||
self.assert_equal(object_type_repr(Ellipsis), 'Ellipsis')
|
||||
|
||||
|
||||
class MarkupLeakTestCase(JinjaTestCase):
|
||||
|
||||
def test_markup_leaks(self):
|
||||
counts = set()
|
||||
for count in xrange(20):
|
||||
for item in xrange(1000):
|
||||
escape("foo")
|
||||
escape("<foo>")
|
||||
escape(u"foo")
|
||||
escape(u"<foo>")
|
||||
counts.add(len(gc.get_objects()))
|
||||
assert len(counts) == 1, 'ouch, c extension seems to leak objects'
|
||||
|
||||
|
||||
def suite():
|
||||
suite = unittest.TestSuite()
|
||||
suite.addTest(unittest.makeSuite(LRUCacheTestCase))
|
||||
suite.addTest(unittest.makeSuite(HelpersTestCase))
|
||||
|
||||
# this test only tests the c extension
|
||||
if not hasattr(escape, 'func_code'):
|
||||
suite.addTest(unittest.makeSuite(MarkupLeakTestCase))
|
||||
|
||||
return suite
|
@ -2,8 +2,8 @@ from string import join
|
||||
from textwrap import fill
|
||||
|
||||
class ParseTree(object):
|
||||
def __init__(self, namespaces=[]):
|
||||
self.namespaces = namespaces
|
||||
def __init__(self, namespaces=None):
|
||||
self.namespaces = namespaces if namespaces else []
|
||||
|
||||
def __str__(self):
|
||||
return join((ns.__str__() for ns in self.namespaces), '\n\n\n')
|
||||
@ -24,7 +24,7 @@ class ParseTree(object):
|
||||
constants.append(obj)
|
||||
else:
|
||||
raise TypeError('Unexpected object type: '+str(type(obj)))
|
||||
self.namespaces.append(Namespace(name, class_tree.values(), functions, constants))
|
||||
self.namespaces.append(Namespace(name, constants, class_tree.values(), functions))
|
||||
|
||||
def insertIntoClassTree(self, obj, class_tree):
|
||||
cname = obj.name if type(obj) is Class else obj.clss
|
||||
@ -106,8 +106,8 @@ class Namespace(object):
|
||||
|
||||
def __str__(self):
|
||||
return 'namespace '+self.name+' {\n\n'+\
|
||||
(join((f.__str__() for f in self.functions), '\n')+'\n\n' if self.functions else '')+\
|
||||
(join((c.__str__() for c in self.constants), '\n')+'\n\n' if self.constants else '')+\
|
||||
(join((f.__str__() for f in self.functions), '\n')+'\n\n' if self.functions else '')+\
|
||||
(join((o.__str__() for o in self.classes), '\n\n') if self.classes else '')+'\n};'
|
||||
|
||||
class Class(object):
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* file: {{class.name}}Bridge.cpp
|
||||
* author: A trusty code generator
|
||||
* date: {{time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime())}}
|
||||
* date: {{time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())}}
|
||||
*
|
||||
* This file was autogenerated, do not modify.
|
||||
* See LICENCE for full modification and redistribution details.
|
||||
* Copyright {{time.strftime("%Y", time.gmtime())}} The OpenCV Foundation
|
||||
* Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
|
||||
*/
|
||||
#include "mex.h"
|
||||
#include "bridge.hpp"
|
||||
|
@ -1,5 +1,9 @@
|
||||
% {{class.name | upper}}
|
||||
% Matlab handle class for OpenCV object classes
|
||||
%
|
||||
% This file was autogenerated, do not modify.
|
||||
% See LICENCE for full modification and redistribution details.
|
||||
% Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
|
||||
classdef {{class.name}} < handle
|
||||
properties (SetAccess = private, Hidden = true)
|
||||
ptr_ = 0; % handle to the underlying c++ class instance
|
||||
|
@ -3,4 +3,4 @@
|
||||
%
|
||||
% See also: {{ fun.doc.see_also }}
|
||||
%
|
||||
% Copyright {{ time.strftime("%Y", gmtime()) }} The OpenCV Foundation
|
||||
% Copyright {{ time.strftime("%Y", localtime()) }} The OpenCV Foundation
|
||||
|
@ -1,11 +1,11 @@
|
||||
/*
|
||||
* file: {{fun.name}}.cpp
|
||||
* author: A trusty code generator
|
||||
* date: {{time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime())}}
|
||||
* date: {{time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())}}
|
||||
*
|
||||
* This file was autogenerated, do not modify.
|
||||
* See LICENCE for full modification and redistribution details.
|
||||
* Copyright {{time.strftime("%Y", time.gmtime())}} The OpenCV Foundation
|
||||
* Copyright {{time.strftime("%Y", time.localtime())}} The OpenCV Foundation
|
||||
*/
|
||||
#include "mex.h"
|
||||
#include "bridge.hpp"
|
||||
|
Loading…
Reference in New Issue
Block a user