updated filters: wordwraps uses the wordwrap module and urlize marks the result as HTML now if in autoescape mode
--HG--
branch : trunk
diff --git a/jinja2/filters.py b/jinja2/filters.py
index 09b1bab..5017156 100644
--- a/jinja2/filters.py
+++ b/jinja2/filters.py
@@ -10,6 +10,7 @@
"""
import re
import math
+import textwrap
from random import choice
from operator import itemgetter
from itertools import imap, groupby
@@ -94,7 +95,7 @@
.. sourcecode:: html+jinja
- <ul{{ {'class': 'my_list', 'missing': None,
+ <ul{{ {'class': 'my_list', 'missing': none,
'id': 'list-%d'|format(variable)}|xmlattr }}>
...
</ul>
@@ -291,7 +292,8 @@
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
@@ -300,10 +302,13 @@
.. 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):
@@ -314,7 +319,7 @@
.. sourcecode:: jinja
- {{ mytext|indent(2, True) }}
+ {{ mytext|indent(2, true) }}
indent by two spaces and indent the first line too.
"""
indention = ' ' * width
@@ -354,26 +359,16 @@
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):
@@ -416,10 +411,10 @@
{{ "%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):
diff --git a/jinja2/lexer.py b/jinja2/lexer.py
index 3b65b95..f01b85d 100644
--- a/jinja2/lexer.py
+++ b/jinja2/lexer.py
@@ -137,7 +137,7 @@
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
@@ -145,7 +145,7 @@
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):
diff --git a/jinja2/loaders.py b/jinja2/loaders.py
index cdda94a..45959a5 100644
--- a/jinja2/loaders.py
+++ b/jinja2/loaders.py
@@ -5,10 +5,6 @@
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.
"""
@@ -259,7 +255,7 @@
>>> 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.
diff --git a/jinja2/parser.py b/jinja2/parser.py
index 4239e25..05d2e32 100644
--- a/jinja2/parser.py
+++ b/jinja2/parser.py
@@ -152,8 +152,7 @@
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()
@@ -722,7 +721,7 @@
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')
diff --git a/jinja2/utils.py b/jinja2/utils.py
index d9a45a8..610e4a1 100644
--- a/jinja2/utils.py
+++ b/jinja2/utils.py
@@ -36,23 +36,24 @@
# 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