- like sum and sort, join now also is able to join attributes of objects
as string.
- the internal eval context now has a reference to the environment.
+- added a mapping test to see if an object is a dict or an object with
+ a similar interface.
Version 2.5.5
-------------
The name Jinja was chosen because it's the name of a Japanese temple and
temple and template share a similar pronunciation. It is not named after
-the capital city of Uganda.
+the city in Uganda.
How fast is it?
---------------
//
Divide two numbers and return the truncated integer result.
- ``{{ 20 / 7 }}`` is ``2``.
+ ``{{ 20 // 7 }}`` is ``2``.
%
Calculate the remainder of an integer division. ``{{ 11 % 7 }}`` is ``4``.
from werkzeug import script
env = jinja2.Environment(extensions=['jinja2.ext.i18n', 'jinja2.ext.do',
- 'jinja2.ext.loopcontrols'])
+ 'jinja2.ext.loopcontrols',
+ 'jinja2.ext.with_',
+ 'jinja2.ext.autoescape'],
+ autoescape=True)
def shell_init_func():
def _compile(x):
import tempfile
import cPickle as pickle
import fnmatch
-from cStringIO import StringIO
try:
from hashlib import sha1
except ImportError:
from jinja2.utils import open_if_exists
+# marshal works better on 3.x, one hack less required
+if sys.version_info > (3, 0):
+ from io import BytesIO
+ marshal_dump = marshal.dump
+ marshal_load = marshal.load
+else:
+ from cStringIO import StringIO as BytesIO
+
+ def marshal_dump(code, f):
+ if isinstance(f, file):
+ marshal.dump(code, f)
+ else:
+ f.write(marshal.dumps(code))
+
+ def marshal_load(f):
+ if isinstance(f, file):
+ return marshal.load(f)
+ return marshal.loads(f.read())
+
+
bc_version = 2
# magic version used to only change with new jinja versions. With 2.6
if self.checksum != checksum:
self.reset()
return
- # now load the code. Because marshal is not able to load
- # from arbitrary streams we have to work around that
- if isinstance(f, file):
- self.code = marshal.load(f)
- else:
- self.code = marshal.loads(f.read())
+ self.code = marshal_load(f)
def write_bytecode(self, f):
"""Dump the bytecode into the file or file like object passed."""
raise TypeError('can\'t write empty bucket')
f.write(bc_magic)
pickle.dump(self.checksum, f, 2)
- if isinstance(f, file):
- marshal.dump(self.code, f)
- else:
- f.write(marshal.dumps(self.code))
+ marshal_dump(code, f)
def bytecode_from_string(self, string):
"""Load bytecode from a string."""
- self.load_bytecode(StringIO(string))
+ self.load_bytecode(BytesIO(string))
def bytecode_to_string(self):
"""Return the bytecode as string."""
- out = StringIO()
+ out = BytesIO()
self.write_bytecode(out)
return out.getvalue()
"""Returns the unique hash key for this template name."""
hash = sha1(name.encode('utf-8'))
if filename is not None:
+ filename = '|' + filename
if isinstance(filename, unicode):
filename = filename.encode('utf-8')
- hash.update('|' + filename)
+ hash.update(filename)
return hash.hexdigest()
def get_source_checksum(self, source):
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
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))
'lower': test_lower,
'upper': test_upper,
'string': test_string,
+ 'mapping': test_mapping,
'number': test_number,
'sequence': test_sequence,
'iterable': test_iterable,
{{ range is callable }}
{{ 42 is callable }}
{{ range(5) is iterable }}
+ {{ {} is mapping }}
+ {{ mydict is mapping }}
+ {{ [] is mapping }}
''')
- assert tmpl.render().split() == [
+ class MyDict(dict):
+ pass
+ assert tmpl.render(mydict=MyDict()).split() == [
'False', 'True', 'False', 'True', 'True', 'False',
- 'True', 'True', 'True', 'True', 'False', 'True'
+ 'True', 'True', 'True', 'True', 'False', 'True',
+ 'True', 'True', 'False'
]
def test_sequence(self):