file system. The environment will keep the compiled modules in memory like
Python's `sys.modules`. Unlike `sys.modules` however this cache is limited in
size by default and templates are automatically reloaded.
+All loaders are subclasses of :class:`BaseLoader`. If you want to create your
+
+own loader, subclass :class:`BaseLoader` and override `get_source`.
+
+.. autoclass:: jinja2.loaders.BaseLoader
+ :members: get_source, load
+
+Here a list of the builtin loaders Jinja2 provides:
.. autoclass:: jinja2.loaders.FileSystemLoader
.. autoclass:: jinja2.loaders.ChoiceLoader
-All loaders are subclasses of :class:`BaseLoader`. If you want to create your
-own loader, subclass :class:`BaseLoader` and override `get_source`.
-
-.. autoclass:: jinja2.loaders.BaseLoader
- :members: get_source, load
-
Utilities
---------
"""
import re
import math
+import textwrap
from random import choice
from operator import itemgetter
from itertools import imap, groupby
.. sourcecode:: html+jinja
- <ul{{ {'class': 'my_list', 'missing': None,
+ <ul{{ {'class': 'my_list', 'missing': none,
'id': 'list-%d'|format(variable)}|xmlattr }}>
...
</ul>
return pformat(value, verbose=verbose)
-def do_urlize(value, trim_url_limit=None, nofollow=False):
+@environmentfilter
+def do_urlize(environment, value, trim_url_limit=None, nofollow=False):
"""Converts URLs in plain text into clickable links.
If you pass the filter an additional integer it will shorten the urls
.. sourcecode:: jinja
- {{ mytext|urlize(40, True) }}
+ {{ mytext|urlize(40, true) }}
links are shortened to 40 chars and defined with rel="nofollow"
"""
- return urlize(soft_unicode(value), trim_url_limit, nofollow)
+ rv = urlize(soft_unicode(value), trim_url_limit, nofollow)
+ if environment.autoescape:
+ rv = Markup(rv)
+ return rv
def do_indent(s, width=4, indentfirst=False):
.. sourcecode:: jinja
- {{ mytext|indent(2, True) }}
+ {{ mytext|indent(2, true) }}
indent by two spaces and indent the first line too.
"""
indention = ' ' * width
return u' '.join(result)
-def do_wordwrap(s, pos=79, hard=False):
+def do_wordwrap(s, width=79, break_long_words=True):
"""
Return a copy of the string passed to the filter wrapped after
- ``79`` characters. You can override this default using the first
- parameter. If you set the second parameter to `true` Jinja will
- also split words apart (usually a bad idea because it makes
- reading hard).
+ ``79`` characters. You can override this default using the first
+ parameter. If you set the second parameter to `false` Jinja will not
+ split words apart if they are longer than `width`.
"""
- if len(s) < pos:
- return s
- if hard:
- return u'\n'.join(s[idx:idx + pos] for idx in
- xrange(0, len(s), pos))
-
- # TODO: switch to wordwrap.wrap
- # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/148061
- return reduce(lambda line, word, pos=pos: u'%s%s%s' %
- (line, u' \n'[(len(line)-line.rfind('\n') - 1 +
- len(word.split('\n', 1)[0]) >= pos)],
- word), s.split(' '))
+ return textwrap.wrap(s, width=width, expand_tabs=False,
+ replace_whitespace=False,
+ break_long_words=break_long_words)
def do_wordcount(s):
{{ "%s - %s"|format("Hello?", "Foo!") }}
-> Hello? - Foo!
"""
- if kwargs:
- kwargs.update(idx, arg in enumerate(args))
- args = kwargs
- return soft_unicode(value) % args
+ if args and kwargs:
+ raise FilterArgumentError('can\'t handle positional and keyword '
+ 'arguments at the same time')
+ return soft_unicode(value) % (kwargs or args)
def do_trim(value):
token type or 'token_type:token_value'. This can only test against
string values!
"""
- # here we do a regular string equality check as test_many is usually
+ # here we do a regular string equality check as test_any is usually
# passed an iterable of not interned strings.
if self.type == expr:
return True
return expr.split(':', 1) == [self.type, self.value]
return False
- def test_many(self, iterable):
+ def test_any(self, *iterable):
"""Test against multiple token expressions."""
for expr in iterable:
if self.test(expr):
Jinja loader classes.
- XXX: move caching from the loaders to environment.get_template and add
- environment overlays that allow to redefine escaping and other things but
- shared the globals and filter mappings.
-
:copyright: 2008 by Armin Ronacher.
:license: BSD, see LICENSE for more details.
"""
>>> loader = ChoiceLoader([
... FileSystemLoader('/path/to/user/templates'),
... PackageLoader('myapplication')
- ])
+ .. ])
This is useful if you want to allow users to override builtin templates
from a different location.
return node
def parse_import_context(self, node, default):
- if (self.stream.current.test('name:with') or
- self.stream.current.test('name:without')) and \
+ if self.stream.current.test_any('name:with', 'name:without') and \
self.stream.look().test('name:context'):
node.with_context = self.stream.next().value == 'with'
self.stream.skip()
flush_data()
self.stream.next()
if end_tokens is not None and \
- self.stream.current.test_many(end_tokens):
+ self.stream.current.test_any(*end_tokens):
return body
body.append(self.parse_statement())
self.stream.expect('block_end')
# concatenate a list of strings and convert them to unicode.
# unfortunately there is a bug in python 2.4 and lower that causes
# unicode.join trash the traceback.
+_concat = u''.join
try:
def _test_gen_bug():
raise TypeError(_test_gen_bug)
yield None
- u''.join(_test_gen_bug())
+ _concat(_test_gen_bug())
except TypeError, _error:
- if _error.args and _error.args[0] is _test_gen_bug:
- concat = u''.join
- else:
+ if not _error.args or _error.args[0] is not _test_gen_bug:
def concat(gen):
try:
- return u''.join(list(gen))
+ return _concat(list(gen))
except:
# this hack is needed so that the current frame
# does not show up in the traceback.
exc_type, exc_value, tb = sys.exc_info()
raise exc_type, exc_value, tb.tb_next
+ else:
+ concat = _concat
del _test_gen_bug, _error