Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(295)

Side by Side Diff: third_party/jinja2/filters.py

Issue 23506004: Update Jinja2 (Python template library) to 2.7.1 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/jinja2/ext.py ('k') | third_party/jinja2/get_jinja2.sh » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # -*- coding: utf-8 -*- 1 # -*- coding: utf-8 -*-
2 """ 2 """
3 jinja2.filters 3 jinja2.filters
4 ~~~~~~~~~~~~~~ 4 ~~~~~~~~~~~~~~
5 5
6 Bundled jinja filters. 6 Bundled jinja filters.
7 7
8 :copyright: (c) 2010 by the Jinja Team. 8 :copyright: (c) 2010 by the Jinja Team.
9 :license: BSD, see LICENSE for more details. 9 :license: BSD, see LICENSE for more details.
10 """ 10 """
11 import re 11 import re
12 import math 12 import math
13
13 from random import choice 14 from random import choice
14 from operator import itemgetter 15 from operator import itemgetter
15 from itertools import imap, groupby 16 from itertools import groupby
16 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode 17 from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \
18 unicode_urlencode
17 from jinja2.runtime import Undefined 19 from jinja2.runtime import Undefined
18 from jinja2.exceptions import FilterArgumentError, SecurityError 20 from jinja2.exceptions import FilterArgumentError
21 from jinja2._compat import next, imap, string_types, text_type, iteritems
19 22
20 23
21 _word_re = re.compile(r'\w+(?u)') 24 _word_re = re.compile(r'\w+(?u)')
22 25
23 26
24 def contextfilter(f): 27 def contextfilter(f):
25 """Decorator for marking context dependent filters. The current 28 """Decorator for marking context dependent filters. The current
26 :class:`Context` will be passed as first argument. 29 :class:`Context` will be passed as first argument.
27 """ 30 """
28 f.contextfilter = True 31 f.contextfilter = True
(...skipping 15 matching lines...) Expand all
44 """Decorator for marking evironment dependent filters. The current 47 """Decorator for marking evironment dependent filters. The current
45 :class:`Environment` is passed to the filter as first argument. 48 :class:`Environment` is passed to the filter as first argument.
46 """ 49 """
47 f.environmentfilter = True 50 f.environmentfilter = True
48 return f 51 return f
49 52
50 53
51 def make_attrgetter(environment, attribute): 54 def make_attrgetter(environment, attribute):
52 """Returns a callable that looks up the given attribute from a 55 """Returns a callable that looks up the given attribute from a
53 passed object with the rules of the environment. Dots are allowed 56 passed object with the rules of the environment. Dots are allowed
54 to access attributes of attributes. 57 to access attributes of attributes. Integer parts in paths are
58 looked up as integers.
55 """ 59 """
56 if not isinstance(attribute, basestring) or '.' not in attribute: 60 if not isinstance(attribute, string_types) \
61 or ('.' not in attribute and not attribute.isdigit()):
57 return lambda x: environment.getitem(x, attribute) 62 return lambda x: environment.getitem(x, attribute)
58 attribute = attribute.split('.') 63 attribute = attribute.split('.')
59 def attrgetter(item): 64 def attrgetter(item):
60 for part in attribute: 65 for part in attribute:
66 if part.isdigit():
67 part = int(part)
61 item = environment.getitem(item, part) 68 item = environment.getitem(item, part)
62 return item 69 return item
63 return attrgetter 70 return attrgetter
64 71
65 72
66 def do_forceescape(value): 73 def do_forceescape(value):
67 """Enforce HTML escaping. This will probably double escape variables.""" 74 """Enforce HTML escaping. This will probably double escape variables."""
68 if hasattr(value, '__html__'): 75 if hasattr(value, '__html__'):
69 value = value.__html__() 76 value = value.__html__()
70 return escape(unicode(value)) 77 return escape(text_type(value))
78
79
80 def do_urlencode(value):
81 """Escape strings for use in URLs (uses UTF-8 encoding). It accepts both
82 dictionaries and regular strings as well as pairwise iterables.
83
84 .. versionadded:: 2.7
85 """
86 itemiter = None
87 if isinstance(value, dict):
88 itemiter = iteritems(value)
89 elif not isinstance(value, string_types):
90 try:
91 itemiter = iter(value)
92 except TypeError:
93 pass
94 if itemiter is None:
95 return unicode_urlencode(value)
96 return u'&'.join(unicode_urlencode(k) + '=' +
97 unicode_urlencode(v) for k, v in itemiter)
71 98
72 99
73 @evalcontextfilter 100 @evalcontextfilter
74 def do_replace(eval_ctx, s, old, new, count=None): 101 def do_replace(eval_ctx, s, old, new, count=None):
75 """Return a copy of the value with all occurrences of a substring 102 """Return a copy of the value with all occurrences of a substring
76 replaced with a new one. The first argument is the substring 103 replaced with a new one. The first argument is the substring
77 that should be replaced, the second is the replacement string. 104 that should be replaced, the second is the replacement string.
78 If the optional third argument ``count`` is given, only the first 105 If the optional third argument ``count`` is given, only the first
79 ``count`` occurrences are replaced: 106 ``count`` occurrences are replaced:
80 107
81 .. sourcecode:: jinja 108 .. sourcecode:: jinja
82 109
83 {{ "Hello World"|replace("Hello", "Goodbye") }} 110 {{ "Hello World"|replace("Hello", "Goodbye") }}
84 -> Goodbye World 111 -> Goodbye World
85 112
86 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} 113 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }}
87 -> d'oh, d'oh, aaargh 114 -> d'oh, d'oh, aaargh
88 """ 115 """
89 if count is None: 116 if count is None:
90 count = -1 117 count = -1
91 if not eval_ctx.autoescape: 118 if not eval_ctx.autoescape:
92 return unicode(s).replace(unicode(old), unicode(new), count) 119 return text_type(s).replace(text_type(old), text_type(new), count)
93 if hasattr(old, '__html__') or hasattr(new, '__html__') and \ 120 if hasattr(old, '__html__') or hasattr(new, '__html__') and \
94 not hasattr(s, '__html__'): 121 not hasattr(s, '__html__'):
95 s = escape(s) 122 s = escape(s)
96 else: 123 else:
97 s = soft_unicode(s) 124 s = soft_unicode(s)
98 return s.replace(soft_unicode(old), soft_unicode(new), count) 125 return s.replace(soft_unicode(old), soft_unicode(new), count)
99 126
100 127
101 def do_upper(s): 128 def do_upper(s):
102 """Convert a value to uppercase.""" 129 """Convert a value to uppercase."""
(...skipping 24 matching lines...) Expand all
127 154
128 <ul class="my_list" id="list-42"> 155 <ul class="my_list" id="list-42">
129 ... 156 ...
130 </ul> 157 </ul>
131 158
132 As you can see it automatically prepends a space in front of the item 159 As you can see it automatically prepends a space in front of the item
133 if the filter returned something unless the second parameter is false. 160 if the filter returned something unless the second parameter is false.
134 """ 161 """
135 rv = u' '.join( 162 rv = u' '.join(
136 u'%s="%s"' % (escape(key), escape(value)) 163 u'%s="%s"' % (escape(key), escape(value))
137 for key, value in d.iteritems() 164 for key, value in iteritems(d)
138 if value is not None and not isinstance(value, Undefined) 165 if value is not None and not isinstance(value, Undefined)
139 ) 166 )
140 if autospace and rv: 167 if autospace and rv:
141 rv = u' ' + rv 168 rv = u' ' + rv
142 if _eval_ctx.autoescape: 169 if _eval_ctx.autoescape:
143 rv = Markup(rv) 170 rv = Markup(rv)
144 return rv 171 return rv
145 172
146 173
147 def do_capitalize(s): 174 def do_capitalize(s):
148 """Capitalize a value. The first character will be uppercase, all others 175 """Capitalize a value. The first character will be uppercase, all others
149 lowercase. 176 lowercase.
150 """ 177 """
151 return soft_unicode(s).capitalize() 178 return soft_unicode(s).capitalize()
152 179
153 180
154 def do_title(s): 181 def do_title(s):
155 """Return a titlecased version of the value. I.e. words will start with 182 """Return a titlecased version of the value. I.e. words will start with
156 uppercase letters, all remaining characters are lowercase. 183 uppercase letters, all remaining characters are lowercase.
157 """ 184 """
158 return soft_unicode(s).title() 185 rv = []
186 for item in re.compile(r'([-\s]+)(?u)').split(s):
187 if not item:
188 continue
189 rv.append(item[0].upper() + item[1:].lower())
190 return ''.join(rv)
159 191
160 192
161 def do_dictsort(value, case_sensitive=False, by='key'): 193 def do_dictsort(value, case_sensitive=False, by='key'):
162 """Sort a dict and yield (key, value) pairs. Because python dicts are 194 """Sort a dict and yield (key, value) pairs. Because python dicts are
163 unsorted you may want to use this function to order them by either 195 unsorted you may want to use this function to order them by either
164 key or value: 196 key or value:
165 197
166 .. sourcecode:: jinja 198 .. sourcecode:: jinja
167 199
168 {% for item in mydict|dictsort %} 200 {% for item in mydict|dictsort %}
169 sort the dict by key, case insensitive 201 sort the dict by key, case insensitive
170 202
171 {% for item in mydict|dicsort(true) %} 203 {% for item in mydict|dictsort(true) %}
172 sort the dict by key, case sensitive 204 sort the dict by key, case sensitive
173 205
174 {% for item in mydict|dictsort(false, 'value') %} 206 {% for item in mydict|dictsort(false, 'value') %}
175 sort the dict by key, case insensitive, sorted 207 sort the dict by key, case insensitive, sorted
176 normally and ordered by value. 208 normally and ordered by value.
177 """ 209 """
178 if by == 'key': 210 if by == 'key':
179 pos = 0 211 pos = 0
180 elif by == 'value': 212 elif by == 'value':
181 pos = 1 213 pos = 1
182 else: 214 else:
183 raise FilterArgumentError('You can only sort by either ' 215 raise FilterArgumentError('You can only sort by either '
184 '"key" or "value"') 216 '"key" or "value"')
185 def sort_func(item): 217 def sort_func(item):
186 value = item[pos] 218 value = item[pos]
187 if isinstance(value, basestring) and not case_sensitive: 219 if isinstance(value, string_types) and not case_sensitive:
188 value = value.lower() 220 value = value.lower()
189 return value 221 return value
190 222
191 return sorted(value.items(), key=sort_func) 223 return sorted(value.items(), key=sort_func)
192 224
193 225
194 @environmentfilter 226 @environmentfilter
195 def do_sort(environment, value, reverse=False, case_sensitive=False, 227 def do_sort(environment, value, reverse=False, case_sensitive=False,
196 attribute=None): 228 attribute=None):
197 """Sort an iterable. Per default it sorts ascending, if you pass it 229 """Sort an iterable. Per default it sorts ascending, if you pass it
(...skipping 16 matching lines...) Expand all
214 246
215 {% for item in iterable|sort(attribute='date') %} 247 {% for item in iterable|sort(attribute='date') %}
216 ... 248 ...
217 {% endfor %} 249 {% endfor %}
218 250
219 .. versionchanged:: 2.6 251 .. versionchanged:: 2.6
220 The `attribute` parameter was added. 252 The `attribute` parameter was added.
221 """ 253 """
222 if not case_sensitive: 254 if not case_sensitive:
223 def sort_func(item): 255 def sort_func(item):
224 if isinstance(item, basestring): 256 if isinstance(item, string_types):
225 item = item.lower() 257 item = item.lower()
226 return item 258 return item
227 else: 259 else:
228 sort_func = None 260 sort_func = None
229 if attribute is not None: 261 if attribute is not None:
230 getter = make_attrgetter(environment, attribute) 262 getter = make_attrgetter(environment, attribute)
231 def sort_func(item, processor=sort_func or (lambda x: x)): 263 def sort_func(item, processor=sort_func or (lambda x: x)):
232 return processor(getter(item)) 264 return processor(getter(item))
233 return sorted(value, key=sort_func, reverse=reverse) 265 return sorted(value, key=sort_func, reverse=reverse)
234 266
235 267
236 def do_default(value, default_value=u'', boolean=False): 268 def do_default(value, default_value=u'', boolean=False):
237 """If the value is undefined it will return the passed default value, 269 """If the value is undefined it will return the passed default value,
238 otherwise the value of the variable: 270 otherwise the value of the variable:
239 271
240 .. sourcecode:: jinja 272 .. sourcecode:: jinja
241 273
242 {{ my_variable|default('my_variable is not defined') }} 274 {{ my_variable|default('my_variable is not defined') }}
243 275
244 This will output the value of ``my_variable`` if the variable was 276 This will output the value of ``my_variable`` if the variable was
245 defined, otherwise ``'my_variable is not defined'``. If you want 277 defined, otherwise ``'my_variable is not defined'``. If you want
246 to use default with variables that evaluate to false you have to 278 to use default with variables that evaluate to false you have to
247 set the second parameter to `true`: 279 set the second parameter to `true`:
248 280
249 .. sourcecode:: jinja 281 .. sourcecode:: jinja
250 282
251 {{ ''|default('the string was empty', true) }} 283 {{ ''|default('the string was empty', true) }}
252 """ 284 """
253 if (boolean and not value) or isinstance(value, Undefined): 285 if isinstance(value, Undefined) or (boolean and not value):
254 return default_value 286 return default_value
255 return value 287 return value
256 288
257 289
258 @evalcontextfilter 290 @evalcontextfilter
259 def do_join(eval_ctx, value, d=u'', attribute=None): 291 def do_join(eval_ctx, value, d=u'', attribute=None):
260 """Return a string which is the concatenation of the strings in the 292 """Return a string which is the concatenation of the strings in the
261 sequence. The separator between elements is an empty string per 293 sequence. The separator between elements is an empty string per
262 default, you can define it with the optional parameter: 294 default, you can define it with the optional parameter:
263 295
(...skipping 12 matching lines...) Expand all
276 {{ users|join(', ', attribute='username') }} 308 {{ users|join(', ', attribute='username') }}
277 309
278 .. versionadded:: 2.6 310 .. versionadded:: 2.6
279 The `attribute` parameter was added. 311 The `attribute` parameter was added.
280 """ 312 """
281 if attribute is not None: 313 if attribute is not None:
282 value = imap(make_attrgetter(eval_ctx.environment, attribute), value) 314 value = imap(make_attrgetter(eval_ctx.environment, attribute), value)
283 315
284 # no automatic escaping? joining is a lot eaiser then 316 # no automatic escaping? joining is a lot eaiser then
285 if not eval_ctx.autoescape: 317 if not eval_ctx.autoescape:
286 return unicode(d).join(imap(unicode, value)) 318 return text_type(d).join(imap(text_type, value))
287 319
288 # if the delimiter doesn't have an html representation we check 320 # if the delimiter doesn't have an html representation we check
289 # if any of the items has. If yes we do a coercion to Markup 321 # if any of the items has. If yes we do a coercion to Markup
290 if not hasattr(d, '__html__'): 322 if not hasattr(d, '__html__'):
291 value = list(value) 323 value = list(value)
292 do_escape = False 324 do_escape = False
293 for idx, item in enumerate(value): 325 for idx, item in enumerate(value):
294 if hasattr(item, '__html__'): 326 if hasattr(item, '__html__'):
295 do_escape = True 327 do_escape = True
296 else: 328 else:
297 value[idx] = unicode(item) 329 value[idx] = text_type(item)
298 if do_escape: 330 if do_escape:
299 d = escape(d) 331 d = escape(d)
300 else: 332 else:
301 d = unicode(d) 333 d = text_type(d)
302 return d.join(value) 334 return d.join(value)
303 335
304 # no html involved, to normal joining 336 # no html involved, to normal joining
305 return soft_unicode(d).join(imap(soft_unicode, value)) 337 return soft_unicode(d).join(imap(soft_unicode, value))
306 338
307 339
308 def do_center(value, width=80): 340 def do_center(value, width=80):
309 """Centers the value in a field of a given width.""" 341 """Centers the value in a field of a given width."""
310 return unicode(value).center(width) 342 return text_type(value).center(width)
311 343
312 344
313 @environmentfilter 345 @environmentfilter
314 def do_first(environment, seq): 346 def do_first(environment, seq):
315 """Return the first item of a sequence.""" 347 """Return the first item of a sequence."""
316 try: 348 try:
317 return iter(seq).next() 349 return next(iter(seq))
318 except StopIteration: 350 except StopIteration:
319 return environment.undefined('No first item, sequence was empty.') 351 return environment.undefined('No first item, sequence was empty.')
320 352
321 353
322 @environmentfilter 354 @environmentfilter
323 def do_last(environment, seq): 355 def do_last(environment, seq):
324 """Return the last item of a sequence.""" 356 """Return the last item of a sequence."""
325 try: 357 try:
326 return iter(reversed(seq)).next() 358 return next(iter(reversed(seq)))
327 except StopIteration: 359 except StopIteration:
328 return environment.undefined('No last item, sequence was empty.') 360 return environment.undefined('No last item, sequence was empty.')
329 361
330 362
331 @environmentfilter 363 @environmentfilter
332 def do_random(environment, seq): 364 def do_random(environment, seq):
333 """Return a random item from the sequence.""" 365 """Return a random item from the sequence."""
334 try: 366 try:
335 return choice(seq) 367 return choice(seq)
336 except IndexError: 368 except IndexError:
337 return environment.undefined('No random item, sequence was empty.') 369 return environment.undefined('No random item, sequence was empty.')
338 370
339 371
340 def do_filesizeformat(value, binary=False): 372 def do_filesizeformat(value, binary=False):
341 """Format the value like a 'human-readable' file size (i.e. 13 kB, 373 """Format the value like a 'human-readable' file size (i.e. 13 kB,
342 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, 374 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega,
343 Giga, etc.), if the second parameter is set to `True` the binary 375 Giga, etc.), if the second parameter is set to `True` the binary
344 prefixes are used (Mebi, Gibi). 376 prefixes are used (Mebi, Gibi).
345 """ 377 """
346 bytes = float(value) 378 bytes = float(value)
347 base = binary and 1024 or 1000 379 base = binary and 1024 or 1000
348 prefixes = [ 380 prefixes = [
349 (binary and "KiB" or "kB"), 381 (binary and 'KiB' or 'kB'),
350 (binary and "MiB" or "MB"), 382 (binary and 'MiB' or 'MB'),
351 (binary and "GiB" or "GB"), 383 (binary and 'GiB' or 'GB'),
352 (binary and "TiB" or "TB"), 384 (binary and 'TiB' or 'TB'),
353 (binary and "PiB" or "PB"), 385 (binary and 'PiB' or 'PB'),
354 (binary and "EiB" or "EB"), 386 (binary and 'EiB' or 'EB'),
355 (binary and "ZiB" or "ZB"), 387 (binary and 'ZiB' or 'ZB'),
356 (binary and "YiB" or "YB") 388 (binary and 'YiB' or 'YB')
357 ] 389 ]
358 if bytes == 1: 390 if bytes == 1:
359 return "1 Byte" 391 return '1 Byte'
360 elif bytes < base: 392 elif bytes < base:
361 return "%d Bytes" % bytes 393 return '%d Bytes' % bytes
362 else: 394 else:
363 for i, prefix in enumerate(prefixes): 395 for i, prefix in enumerate(prefixes):
364 unit = base * base ** (i + 1) 396 unit = base ** (i + 2)
365 if bytes < unit: 397 if bytes < unit:
366 return "%.1f %s" % ((bytes / unit), prefix) 398 return '%.1f %s' % ((base * bytes / unit), prefix)
367 return "%.1f %s" % ((bytes / unit), prefix) 399 return '%.1f %s' % ((base * bytes / unit), prefix)
368 400
369 401
370 def do_pprint(value, verbose=False): 402 def do_pprint(value, verbose=False):
371 """Pretty print a variable. Useful for debugging. 403 """Pretty print a variable. Useful for debugging.
372 404
373 With Jinja 1.2 onwards you can pass it a parameter. If this parameter 405 With Jinja 1.2 onwards you can pass it a parameter. If this parameter
374 is truthy the output will be more verbose (this requires `pretty`) 406 is truthy the output will be more verbose (this requires `pretty`)
375 """ 407 """
376 return pformat(value, verbose=verbose) 408 return pformat(value, verbose=verbose)
377 409
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
410 rv = (u'\n' + indention).join(s.splitlines()) 442 rv = (u'\n' + indention).join(s.splitlines())
411 if indentfirst: 443 if indentfirst:
412 rv = indention + rv 444 rv = indention + rv
413 return rv 445 return rv
414 446
415 447
416 def do_truncate(s, length=255, killwords=False, end='...'): 448 def do_truncate(s, length=255, killwords=False, end='...'):
417 """Return a truncated copy of the string. The length is specified 449 """Return a truncated copy of the string. The length is specified
418 with the first parameter which defaults to ``255``. If the second 450 with the first parameter which defaults to ``255``. If the second
419 parameter is ``true`` the filter will cut the text at length. Otherwise 451 parameter is ``true`` the filter will cut the text at length. Otherwise
420 it will try to save the last word. If the text was in fact 452 it will discard the last word. If the text was in fact
421 truncated it will append an ellipsis sign (``"..."``). If you want a 453 truncated it will append an ellipsis sign (``"..."``). If you want a
422 different ellipsis sign than ``"..."`` you can specify it using the 454 different ellipsis sign than ``"..."`` you can specify it using the
423 third parameter. 455 third parameter.
424 456
425 .. sourcecode jinja:: 457 .. sourcecode:: jinja
426 458
427 {{ mytext|truncate(300, false, '&raquo;') }} 459 {{ "foo bar"|truncate(5) }}
428 truncate mytext to 300 chars, don't split up words, use a 460 -> "foo ..."
429 right pointing double arrow as ellipsis sign. 461 {{ "foo bar"|truncate(5, True) }}
462 -> "foo b..."
430 """ 463 """
431 if len(s) <= length: 464 if len(s) <= length:
432 return s 465 return s
433 elif killwords: 466 elif killwords:
434 return s[:length] + end 467 return s[:length] + end
435 words = s.split(' ') 468 words = s.split(' ')
436 result = [] 469 result = []
437 m = 0 470 m = 0
438 for word in words: 471 for word in words:
439 m += len(word) + 1 472 m += len(word) + 1
440 if m > length: 473 if m > length:
441 break 474 break
442 result.append(word) 475 result.append(word)
443 result.append(end) 476 result.append(end)
444 return u' '.join(result) 477 return u' '.join(result)
445 478
446 @environmentfilter 479 @environmentfilter
447 def do_wordwrap(environment, s, width=79, break_long_words=True): 480 def do_wordwrap(environment, s, width=79, break_long_words=True,
481 wrapstring=None):
448 """ 482 """
449 Return a copy of the string passed to the filter wrapped after 483 Return a copy of the string passed to the filter wrapped after
450 ``79`` characters. You can override this default using the first 484 ``79`` characters. You can override this default using the first
451 parameter. If you set the second parameter to `false` Jinja will not 485 parameter. If you set the second parameter to `false` Jinja will not
452 split words apart if they are longer than `width`. 486 split words apart if they are longer than `width`. By default, the newlines
487 will be the default newlines for the environment, but this can be changed
488 using the wrapstring keyword argument.
489
490 .. versionadded:: 2.7
491 Added support for the `wrapstring` parameter.
453 """ 492 """
493 if not wrapstring:
494 wrapstring = environment.newline_sequence
454 import textwrap 495 import textwrap
455 return environment.newline_sequence.join(textwrap.wrap(s, width=width, expan d_tabs=False, 496 return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False,
456 replace_whitespace=False, 497 replace_whitespace=False,
457 break_long_words=break_long_words)) 498 break_long_words=break_long_words))
458 499
459 500
460 def do_wordcount(s): 501 def do_wordcount(s):
461 """Count the words in that string.""" 502 """Count the words in that string."""
462 return len(_word_re.findall(s)) 503 return len(_word_re.findall(s))
463 504
464 505
465 def do_int(value, default=0): 506 def do_int(value, default=0):
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
506 def do_trim(value): 547 def do_trim(value):
507 """Strip leading and trailing whitespace.""" 548 """Strip leading and trailing whitespace."""
508 return soft_unicode(value).strip() 549 return soft_unicode(value).strip()
509 550
510 551
511 def do_striptags(value): 552 def do_striptags(value):
512 """Strip SGML/XML tags and replace adjacent whitespace by one space. 553 """Strip SGML/XML tags and replace adjacent whitespace by one space.
513 """ 554 """
514 if hasattr(value, '__html__'): 555 if hasattr(value, '__html__'):
515 value = value.__html__() 556 value = value.__html__()
516 return Markup(unicode(value)).striptags() 557 return Markup(text_type(value)).striptags()
517 558
518 559
519 def do_slice(value, slices, fill_with=None): 560 def do_slice(value, slices, fill_with=None):
520 """Slice an iterator and return a list of lists containing 561 """Slice an iterator and return a list of lists containing
521 those items. Useful if you want to create a div containing 562 those items. Useful if you want to create a div containing
522 three ul tags that represent columns: 563 three ul tags that represent columns:
523 564
524 .. sourcecode:: html+jinja 565 .. sourcecode:: html+jinja
525 566
526 <div class="columwrapper"> 567 <div class="columwrapper">
527 {%- for column in items|slice(3) %} 568 {%- for column in items|slice(3) %}
528 <ul class="column-{{ loop.index }}"> 569 <ul class="column-{{ loop.index }}">
529 {%- for item in column %} 570 {%- for item in column %}
530 <li>{{ item }}</li> 571 <li>{{ item }}</li>
531 {%- endfor %} 572 {%- endfor %}
532 </ul> 573 </ul>
533 {%- endfor %} 574 {%- endfor %}
534 </div> 575 </div>
535 576
536 If you pass it a second argument it's used to fill missing 577 If you pass it a second argument it's used to fill missing
537 values on the last iteration. 578 values on the last iteration.
538 """ 579 """
539 seq = list(value) 580 seq = list(value)
540 length = len(seq) 581 length = len(seq)
541 items_per_slice = length // slices 582 items_per_slice = length // slices
542 slices_with_extra = length % slices 583 slices_with_extra = length % slices
543 offset = 0 584 offset = 0
544 for slice_number in xrange(slices): 585 for slice_number in range(slices):
545 start = offset + slice_number * items_per_slice 586 start = offset + slice_number * items_per_slice
546 if slice_number < slices_with_extra: 587 if slice_number < slices_with_extra:
547 offset += 1 588 offset += 1
548 end = offset + (slice_number + 1) * items_per_slice 589 end = offset + (slice_number + 1) * items_per_slice
549 tmp = seq[start:end] 590 tmp = seq[start:end]
550 if fill_with is not None and slice_number >= slices_with_extra: 591 if fill_with is not None and slice_number >= slices_with_extra:
551 tmp.append(fill_with) 592 tmp.append(fill_with)
552 yield tmp 593 yield tmp
553 594
554 595
555 def do_batch(value, linecount, fill_with=None): 596 def do_batch(value, linecount, fill_with=None):
556 """ 597 """
557 A filter that batches items. It works pretty much like `slice` 598 A filter that batches items. It works pretty much like `slice`
558 just the other way round. It returns a list of lists with the 599 just the other way round. It returns a list of lists with the
559 given number of items. If you provide a second parameter this 600 given number of items. If you provide a second parameter this
560 is used to fill missing items. See this example: 601 is used to fill up missing items. See this example:
561 602
562 .. sourcecode:: html+jinja 603 .. sourcecode:: html+jinja
563 604
564 <table> 605 <table>
565 {%- for row in items|batch(3, '&nbsp;') %} 606 {%- for row in items|batch(3, '&nbsp;') %}
566 <tr> 607 <tr>
567 {%- for column in row %} 608 {%- for column in row %}
568 <td>{{ column }}</td> 609 <td>{{ column }}</td>
569 {%- endfor %} 610 {%- endfor %}
570 </tr> 611 </tr>
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
659 """ 700 """
660 expr = make_attrgetter(environment, attribute) 701 expr = make_attrgetter(environment, attribute)
661 return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr))) 702 return sorted(map(_GroupTuple, groupby(sorted(value, key=expr), expr)))
662 703
663 704
664 class _GroupTuple(tuple): 705 class _GroupTuple(tuple):
665 __slots__ = () 706 __slots__ = ()
666 grouper = property(itemgetter(0)) 707 grouper = property(itemgetter(0))
667 list = property(itemgetter(1)) 708 list = property(itemgetter(1))
668 709
669 def __new__(cls, (key, value)): 710 def __new__(cls, xxx_todo_changeme):
711 (key, value) = xxx_todo_changeme
670 return tuple.__new__(cls, (key, list(value))) 712 return tuple.__new__(cls, (key, list(value)))
671 713
672 714
673 @environmentfilter 715 @environmentfilter
674 def do_sum(environment, iterable, attribute=None, start=0): 716 def do_sum(environment, iterable, attribute=None, start=0):
675 """Returns the sum of a sequence of numbers plus the value of parameter 717 """Returns the sum of a sequence of numbers plus the value of parameter
676 'start' (which defaults to 0). When the sequence is empty it returns 718 'start' (which defaults to 0). When the sequence is empty it returns
677 start. 719 start.
678 720
679 It is also possible to sum up only certain attributes: 721 It is also possible to sum up only certain attributes:
(...skipping 20 matching lines...) Expand all
700 742
701 def do_mark_safe(value): 743 def do_mark_safe(value):
702 """Mark the value as safe which means that in an environment with automatic 744 """Mark the value as safe which means that in an environment with automatic
703 escaping enabled this variable will not be escaped. 745 escaping enabled this variable will not be escaped.
704 """ 746 """
705 return Markup(value) 747 return Markup(value)
706 748
707 749
708 def do_mark_unsafe(value): 750 def do_mark_unsafe(value):
709 """Mark a value as unsafe. This is the reverse operation for :func:`safe`." "" 751 """Mark a value as unsafe. This is the reverse operation for :func:`safe`." ""
710 return unicode(value) 752 return text_type(value)
711 753
712 754
713 def do_reverse(value): 755 def do_reverse(value):
714 """Reverse the object or return an iterator the iterates over it the other 756 """Reverse the object or return an iterator the iterates over it the other
715 way round. 757 way round.
716 """ 758 """
717 if isinstance(value, basestring): 759 if isinstance(value, string_types):
718 return value[::-1] 760 return value[::-1]
719 try: 761 try:
720 return reversed(value) 762 return reversed(value)
721 except TypeError: 763 except TypeError:
722 try: 764 try:
723 rv = list(value) 765 rv = list(value)
724 rv.reverse() 766 rv.reverse()
725 return rv 767 return rv
726 except TypeError: 768 except TypeError:
727 raise FilterArgumentError('argument must be iterable') 769 raise FilterArgumentError('argument must be iterable')
(...skipping 17 matching lines...) Expand all
745 except AttributeError: 787 except AttributeError:
746 pass 788 pass
747 else: 789 else:
748 if environment.sandboxed and not \ 790 if environment.sandboxed and not \
749 environment.is_safe_attribute(obj, name, value): 791 environment.is_safe_attribute(obj, name, value):
750 return environment.unsafe_undefined(obj, name) 792 return environment.unsafe_undefined(obj, name)
751 return value 793 return value
752 return environment.undefined(obj=obj, name=name) 794 return environment.undefined(obj=obj, name=name)
753 795
754 796
797 @contextfilter
798 def do_map(*args, **kwargs):
799 """Applies a filter on a sequence of objects or looks up an attribute.
800 This is useful when dealing with lists of objects but you are really
801 only interested in a certain value of it.
802
803 The basic usage is mapping on an attribute. Imagine you have a list
804 of users but you are only interested in a list of usernames:
805
806 .. sourcecode:: jinja
807
808 Users on this page: {{ users|map(attribute='username')|join(', ') }}
809
810 Alternatively you can let it invoke a filter by passing the name of the
811 filter and the arguments afterwards. A good example would be applying a
812 text conversion filter on a sequence:
813
814 .. sourcecode:: jinja
815
816 Users on this page: {{ titles|map('lower')|join(', ') }}
817
818 .. versionadded:: 2.7
819 """
820 context = args[0]
821 seq = args[1]
822
823 if len(args) == 2 and 'attribute' in kwargs:
824 attribute = kwargs.pop('attribute')
825 if kwargs:
826 raise FilterArgumentError('Unexpected keyword argument %r' %
827 next(iter(kwargs)))
828 func = make_attrgetter(context.environment, attribute)
829 else:
830 try:
831 name = args[2]
832 args = args[3:]
833 except LookupError:
834 raise FilterArgumentError('map requires a filter argument')
835 func = lambda item: context.environment.call_filter(
836 name, item, args, kwargs, context=context)
837
838 if seq:
839 for item in seq:
840 yield func(item)
841
842
843 @contextfilter
844 def do_select(*args, **kwargs):
845 """Filters a sequence of objects by appying a test to either the object
846 or the attribute and only selecting the ones with the test succeeding.
847
848 Example usage:
849
850 .. sourcecode:: jinja
851
852 {{ numbers|select("odd") }}
853
854 .. versionadded:: 2.7
855 """
856 return _select_or_reject(args, kwargs, lambda x: x, False)
857
858
859 @contextfilter
860 def do_reject(*args, **kwargs):
861 """Filters a sequence of objects by appying a test to either the object
862 or the attribute and rejecting the ones with the test succeeding.
863
864 Example usage:
865
866 .. sourcecode:: jinja
867
868 {{ numbers|reject("odd") }}
869
870 .. versionadded:: 2.7
871 """
872 return _select_or_reject(args, kwargs, lambda x: not x, False)
873
874
875 @contextfilter
876 def do_selectattr(*args, **kwargs):
877 """Filters a sequence of objects by appying a test to either the object
878 or the attribute and only selecting the ones with the test succeeding.
879
880 Example usage:
881
882 .. sourcecode:: jinja
883
884 {{ users|selectattr("is_active") }}
885 {{ users|selectattr("email", "none") }}
886
887 .. versionadded:: 2.7
888 """
889 return _select_or_reject(args, kwargs, lambda x: x, True)
890
891
892 @contextfilter
893 def do_rejectattr(*args, **kwargs):
894 """Filters a sequence of objects by appying a test to either the object
895 or the attribute and rejecting the ones with the test succeeding.
896
897 .. sourcecode:: jinja
898
899 {{ users|rejectattr("is_active") }}
900 {{ users|rejectattr("email", "none") }}
901
902 .. versionadded:: 2.7
903 """
904 return _select_or_reject(args, kwargs, lambda x: not x, True)
905
906
907 def _select_or_reject(args, kwargs, modfunc, lookup_attr):
908 context = args[0]
909 seq = args[1]
910 if lookup_attr:
911 try:
912 attr = args[2]
913 except LookupError:
914 raise FilterArgumentError('Missing parameter for attribute name')
915 transfunc = make_attrgetter(context.environment, attr)
916 off = 1
917 else:
918 off = 0
919 transfunc = lambda x: x
920
921 try:
922 name = args[2 + off]
923 args = args[3 + off:]
924 func = lambda item: context.environment.call_test(
925 name, item, args, kwargs)
926 except LookupError:
927 func = bool
928
929 if seq:
930 for item in seq:
931 if modfunc(func(transfunc(item))):
932 yield item
933
934
755 FILTERS = { 935 FILTERS = {
756 'attr': do_attr, 936 'attr': do_attr,
757 'replace': do_replace, 937 'replace': do_replace,
758 'upper': do_upper, 938 'upper': do_upper,
759 'lower': do_lower, 939 'lower': do_lower,
760 'escape': escape, 940 'escape': escape,
761 'e': escape, 941 'e': escape,
762 'forceescape': do_forceescape, 942 'forceescape': do_forceescape,
763 'capitalize': do_capitalize, 943 'capitalize': do_capitalize,
764 'title': do_title, 944 'title': do_title,
765 'default': do_default, 945 'default': do_default,
766 'd': do_default, 946 'd': do_default,
767 'join': do_join, 947 'join': do_join,
768 'count': len, 948 'count': len,
769 'dictsort': do_dictsort, 949 'dictsort': do_dictsort,
770 'sort': do_sort, 950 'sort': do_sort,
771 'length': len, 951 'length': len,
772 'reverse': do_reverse, 952 'reverse': do_reverse,
773 'center': do_center, 953 'center': do_center,
774 'indent': do_indent, 954 'indent': do_indent,
775 'title': do_title, 955 'title': do_title,
776 'capitalize': do_capitalize, 956 'capitalize': do_capitalize,
777 'first': do_first, 957 'first': do_first,
778 'last': do_last, 958 'last': do_last,
959 'map': do_map,
779 'random': do_random, 960 'random': do_random,
961 'reject': do_reject,
962 'rejectattr': do_rejectattr,
780 'filesizeformat': do_filesizeformat, 963 'filesizeformat': do_filesizeformat,
781 'pprint': do_pprint, 964 'pprint': do_pprint,
782 'truncate': do_truncate, 965 'truncate': do_truncate,
783 'wordwrap': do_wordwrap, 966 'wordwrap': do_wordwrap,
784 'wordcount': do_wordcount, 967 'wordcount': do_wordcount,
785 'int': do_int, 968 'int': do_int,
786 'float': do_float, 969 'float': do_float,
787 'string': soft_unicode, 970 'string': soft_unicode,
788 'list': do_list, 971 'list': do_list,
789 'urlize': do_urlize, 972 'urlize': do_urlize,
790 'format': do_format, 973 'format': do_format,
791 'trim': do_trim, 974 'trim': do_trim,
792 'striptags': do_striptags, 975 'striptags': do_striptags,
976 'select': do_select,
977 'selectattr': do_selectattr,
793 'slice': do_slice, 978 'slice': do_slice,
794 'batch': do_batch, 979 'batch': do_batch,
795 'sum': do_sum, 980 'sum': do_sum,
796 'abs': abs, 981 'abs': abs,
797 'round': do_round, 982 'round': do_round,
798 'groupby': do_groupby, 983 'groupby': do_groupby,
799 'safe': do_mark_safe, 984 'safe': do_mark_safe,
800 'xmlattr': do_xmlattr 985 'xmlattr': do_xmlattr,
986 'urlencode': do_urlencode
801 } 987 }
OLDNEW
« no previous file with comments | « third_party/jinja2/ext.py ('k') | third_party/jinja2/get_jinja2.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698