1# -*- coding: utf-8 -*- 2""" 3 jinja2.filters 4 ~~~~~~~~~~~~~~ 5 6 Bundled jinja filters. 7 8 :copyright: (c) 2017 by the Jinja Team. 9 :license: BSD, see LICENSE for more details. 10""" 11import re 12import math 13 14from random import choice 15from itertools import groupby 16from collections import namedtuple 17from jinja2.utils import Markup, escape, pformat, urlize, soft_unicode, \ 18 unicode_urlencode, htmlsafe_json_dumps 19from jinja2.runtime import Undefined 20from jinja2.exceptions import FilterArgumentError 21from jinja2._compat import imap, string_types, text_type, iteritems, PY2 22 23 24_word_re = re.compile(r'\w+', re.UNICODE) 25_word_beginning_split_re = re.compile(r'([-\s\(\{\[\<]+)', re.UNICODE) 26 27 28def contextfilter(f): 29 """Decorator for marking context dependent filters. The current 30 :class:`Context` will be passed as first argument. 31 """ 32 f.contextfilter = True 33 return f 34 35 36def evalcontextfilter(f): 37 """Decorator for marking eval-context dependent filters. An eval 38 context object is passed as first argument. For more information 39 about the eval context, see :ref:`eval-context`. 40 41 .. versionadded:: 2.4 42 """ 43 f.evalcontextfilter = True 44 return f 45 46 47def environmentfilter(f): 48 """Decorator for marking environment dependent filters. The current 49 :class:`Environment` is passed to the filter as first argument. 50 """ 51 f.environmentfilter = True 52 return f 53 54 55def make_attrgetter(environment, attribute): 56 """Returns a callable that looks up the given attribute from a 57 passed object with the rules of the environment. Dots are allowed 58 to access attributes of attributes. Integer parts in paths are 59 looked up as integers. 60 """ 61 if not isinstance(attribute, string_types) \ 62 or ('.' not in attribute and not attribute.isdigit()): 63 return lambda x: environment.getitem(x, attribute) 64 attribute = attribute.split('.') 65 def attrgetter(item): 66 for part in attribute: 67 if part.isdigit(): 68 part = int(part) 69 item = environment.getitem(item, part) 70 return item 71 return attrgetter 72 73 74def do_forceescape(value): 75 """Enforce HTML escaping. This will probably double escape variables.""" 76 if hasattr(value, '__html__'): 77 value = value.__html__() 78 return escape(text_type(value)) 79 80 81def do_urlencode(value): 82 """Escape strings for use in URLs (uses UTF-8 encoding). It accepts both 83 dictionaries and regular strings as well as pairwise iterables. 84 85 .. versionadded:: 2.7 86 """ 87 itemiter = None 88 if isinstance(value, dict): 89 itemiter = iteritems(value) 90 elif not isinstance(value, string_types): 91 try: 92 itemiter = iter(value) 93 except TypeError: 94 pass 95 if itemiter is None: 96 return unicode_urlencode(value) 97 return u'&'.join(unicode_urlencode(k) + '=' + 98 unicode_urlencode(v, for_qs=True) 99 for k, v in itemiter) 100 101 102@evalcontextfilter 103def do_replace(eval_ctx, s, old, new, count=None): 104 """Return a copy of the value with all occurrences of a substring 105 replaced with a new one. The first argument is the substring 106 that should be replaced, the second is the replacement string. 107 If the optional third argument ``count`` is given, only the first 108 ``count`` occurrences are replaced: 109 110 .. sourcecode:: jinja 111 112 {{ "Hello World"|replace("Hello", "Goodbye") }} 113 -> Goodbye World 114 115 {{ "aaaaargh"|replace("a", "d'oh, ", 2) }} 116 -> d'oh, d'oh, aaargh 117 """ 118 if count is None: 119 count = -1 120 if not eval_ctx.autoescape: 121 return text_type(s).replace(text_type(old), text_type(new), count) 122 if hasattr(old, '__html__') or hasattr(new, '__html__') and \ 123 not hasattr(s, '__html__'): 124 s = escape(s) 125 else: 126 s = soft_unicode(s) 127 return s.replace(soft_unicode(old), soft_unicode(new), count) 128 129 130def do_upper(s): 131 """Convert a value to uppercase.""" 132 return soft_unicode(s).upper() 133 134 135def do_lower(s): 136 """Convert a value to lowercase.""" 137 return soft_unicode(s).lower() 138 139 140@evalcontextfilter 141def do_xmlattr(_eval_ctx, d, autospace=True): 142 """Create an SGML/XML attribute string based on the items in a dict. 143 All values that are neither `none` nor `undefined` are automatically 144 escaped: 145 146 .. sourcecode:: html+jinja 147 148 <ul{{ {'class': 'my_list', 'missing': none, 149 'id': 'list-%d'|format(variable)}|xmlattr }}> 150 ... 151 </ul> 152 153 Results in something like this: 154 155 .. sourcecode:: html 156 157 <ul class="my_list" id="list-42"> 158 ... 159 </ul> 160 161 As you can see it automatically prepends a space in front of the item 162 if the filter returned something unless the second parameter is false. 163 """ 164 rv = u' '.join( 165 u'%s="%s"' % (escape(key), escape(value)) 166 for key, value in iteritems(d) 167 if value is not None and not isinstance(value, Undefined) 168 ) 169 if autospace and rv: 170 rv = u' ' + rv 171 if _eval_ctx.autoescape: 172 rv = Markup(rv) 173 return rv 174 175 176def do_capitalize(s): 177 """Capitalize a value. The first character will be uppercase, all others 178 lowercase. 179 """ 180 return soft_unicode(s).capitalize() 181 182 183def do_title(s): 184 """Return a titlecased version of the value. I.e. words will start with 185 uppercase letters, all remaining characters are lowercase. 186 """ 187 return ''.join( 188 [item[0].upper() + item[1:].lower() 189 for item in _word_beginning_split_re.split(soft_unicode(s)) 190 if item]) 191 192 193def do_dictsort(value, case_sensitive=False, by='key'): 194 """Sort a dict and yield (key, value) pairs. Because python dicts are 195 unsorted you may want to use this function to order them by either 196 key or value: 197 198 .. sourcecode:: jinja 199 200 {% for item in mydict|dictsort %} 201 sort the dict by key, case insensitive 202 203 {% for item in mydict|dictsort(true) %} 204 sort the dict by key, case sensitive 205 206 {% for item in mydict|dictsort(false, 'value') %} 207 sort the dict by value, case insensitive 208 """ 209 if by == 'key': 210 pos = 0 211 elif by == 'value': 212 pos = 1 213 else: 214 raise FilterArgumentError('You can only sort by either ' 215 '"key" or "value"') 216 def sort_func(item): 217 value = item[pos] 218 if isinstance(value, string_types) and not case_sensitive: 219 value = value.lower() 220 return value 221 222 return sorted(value.items(), key=sort_func) 223 224 225@environmentfilter 226def do_sort(environment, value, reverse=False, case_sensitive=False, 227 attribute=None): 228 """Sort an iterable. Per default it sorts ascending, if you pass it 229 true as first argument it will reverse the sorting. 230 231 If the iterable is made of strings the third parameter can be used to 232 control the case sensitiveness of the comparison which is disabled by 233 default. 234 235 .. sourcecode:: jinja 236 237 {% for item in iterable|sort %} 238 ... 239 {% endfor %} 240 241 It is also possible to sort by an attribute (for example to sort 242 by the date of an object) by specifying the `attribute` parameter: 243 244 .. sourcecode:: jinja 245 246 {% for item in iterable|sort(attribute='date') %} 247 ... 248 {% endfor %} 249 250 .. versionchanged:: 2.6 251 The `attribute` parameter was added. 252 """ 253 if not case_sensitive: 254 def sort_func(item): 255 if isinstance(item, string_types): 256 item = item.lower() 257 return item 258 else: 259 sort_func = None 260 if attribute is not None: 261 getter = make_attrgetter(environment, attribute) 262 def sort_func(item, processor=sort_func or (lambda x: x)): 263 return processor(getter(item)) 264 return sorted(value, key=sort_func, reverse=reverse) 265 266 267def do_default(value, default_value=u'', boolean=False): 268 """If the value is undefined it will return the passed default value, 269 otherwise the value of the variable: 270 271 .. sourcecode:: jinja 272 273 {{ my_variable|default('my_variable is not defined') }} 274 275 This will output the value of ``my_variable`` if the variable was 276 defined, otherwise ``'my_variable is not defined'``. If you want 277 to use default with variables that evaluate to false you have to 278 set the second parameter to `true`: 279 280 .. sourcecode:: jinja 281 282 {{ ''|default('the string was empty', true) }} 283 """ 284 if isinstance(value, Undefined) or (boolean and not value): 285 return default_value 286 return value 287 288 289@evalcontextfilter 290def do_join(eval_ctx, value, d=u'', attribute=None): 291 """Return a string which is the concatenation of the strings in the 292 sequence. The separator between elements is an empty string per 293 default, you can define it with the optional parameter: 294 295 .. sourcecode:: jinja 296 297 {{ [1, 2, 3]|join('|') }} 298 -> 1|2|3 299 300 {{ [1, 2, 3]|join }} 301 -> 123 302 303 It is also possible to join certain attributes of an object: 304 305 .. sourcecode:: jinja 306 307 {{ users|join(', ', attribute='username') }} 308 309 .. versionadded:: 2.6 310 The `attribute` parameter was added. 311 """ 312 if attribute is not None: 313 value = imap(make_attrgetter(eval_ctx.environment, attribute), value) 314 315 # no automatic escaping? joining is a lot eaiser then 316 if not eval_ctx.autoescape: 317 return text_type(d).join(imap(text_type, value)) 318 319 # if the delimiter doesn't have an html representation we check 320 # if any of the items has. If yes we do a coercion to Markup 321 if not hasattr(d, '__html__'): 322 value = list(value) 323 do_escape = False 324 for idx, item in enumerate(value): 325 if hasattr(item, '__html__'): 326 do_escape = True 327 else: 328 value[idx] = text_type(item) 329 if do_escape: 330 d = escape(d) 331 else: 332 d = text_type(d) 333 return d.join(value) 334 335 # no html involved, to normal joining 336 return soft_unicode(d).join(imap(soft_unicode, value)) 337 338 339def do_center(value, width=80): 340 """Centers the value in a field of a given width.""" 341 return text_type(value).center(width) 342 343 344@environmentfilter 345def do_first(environment, seq): 346 """Return the first item of a sequence.""" 347 try: 348 return next(iter(seq)) 349 except StopIteration: 350 return environment.undefined('No first item, sequence was empty.') 351 352 353@environmentfilter 354def do_last(environment, seq): 355 """Return the last item of a sequence.""" 356 try: 357 return next(iter(reversed(seq))) 358 except StopIteration: 359 return environment.undefined('No last item, sequence was empty.') 360 361 362@environmentfilter 363def do_random(environment, seq): 364 """Return a random item from the sequence.""" 365 try: 366 return choice(seq) 367 except IndexError: 368 return environment.undefined('No random item, sequence was empty.') 369 370 371def do_filesizeformat(value, binary=False): 372 """Format the value like a 'human-readable' file size (i.e. 13 kB, 373 4.1 MB, 102 Bytes, etc). Per default decimal prefixes are used (Mega, 374 Giga, etc.), if the second parameter is set to `True` the binary 375 prefixes are used (Mebi, Gibi). 376 """ 377 bytes = float(value) 378 base = binary and 1024 or 1000 379 prefixes = [ 380 (binary and 'KiB' or 'kB'), 381 (binary and 'MiB' or 'MB'), 382 (binary and 'GiB' or 'GB'), 383 (binary and 'TiB' or 'TB'), 384 (binary and 'PiB' or 'PB'), 385 (binary and 'EiB' or 'EB'), 386 (binary and 'ZiB' or 'ZB'), 387 (binary and 'YiB' or 'YB') 388 ] 389 if bytes == 1: 390 return '1 Byte' 391 elif bytes < base: 392 return '%d Bytes' % bytes 393 else: 394 for i, prefix in enumerate(prefixes): 395 unit = base ** (i + 2) 396 if bytes < unit: 397 return '%.1f %s' % ((base * bytes / unit), prefix) 398 return '%.1f %s' % ((base * bytes / unit), prefix) 399 400 401def do_pprint(value, verbose=False): 402 """Pretty print a variable. Useful for debugging. 403 404 With Jinja 1.2 onwards you can pass it a parameter. If this parameter 405 is truthy the output will be more verbose (this requires `pretty`) 406 """ 407 return pformat(value, verbose=verbose) 408 409 410@evalcontextfilter 411def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False, 412 target=None, rel=None): 413 """Converts URLs in plain text into clickable links. 414 415 If you pass the filter an additional integer it will shorten the urls 416 to that number. Also a third argument exists that makes the urls 417 "nofollow": 418 419 .. sourcecode:: jinja 420 421 {{ mytext|urlize(40, true) }} 422 links are shortened to 40 chars and defined with rel="nofollow" 423 424 If *target* is specified, the ``target`` attribute will be added to the 425 ``<a>`` tag: 426 427 .. sourcecode:: jinja 428 429 {{ mytext|urlize(40, target='_blank') }} 430 431 .. versionchanged:: 2.8+ 432 The *target* parameter was added. 433 """ 434 policies = eval_ctx.environment.policies 435 rel = set((rel or '').split() or []) 436 if nofollow: 437 rel.add('nofollow') 438 rel.update((policies['urlize.rel'] or '').split()) 439 if target is None: 440 target = policies['urlize.target'] 441 rel = ' '.join(sorted(rel)) or None 442 rv = urlize(value, trim_url_limit, rel=rel, target=target) 443 if eval_ctx.autoescape: 444 rv = Markup(rv) 445 return rv 446 447 448def do_indent(s, width=4, indentfirst=False): 449 """Return a copy of the passed string, each line indented by 450 4 spaces. The first line is not indented. If you want to 451 change the number of spaces or indent the first line too 452 you can pass additional parameters to the filter: 453 454 .. sourcecode:: jinja 455 456 {{ mytext|indent(2, true) }} 457 indent by two spaces and indent the first line too. 458 """ 459 indention = u' ' * width 460 rv = (u'\n' + indention).join(s.splitlines()) 461 if indentfirst: 462 rv = indention + rv 463 return rv 464 465 466@environmentfilter 467def do_truncate(env, s, length=255, killwords=False, end='...', leeway=None): 468 """Return a truncated copy of the string. The length is specified 469 with the first parameter which defaults to ``255``. If the second 470 parameter is ``true`` the filter will cut the text at length. Otherwise 471 it will discard the last word. If the text was in fact 472 truncated it will append an ellipsis sign (``"..."``). If you want a 473 different ellipsis sign than ``"..."`` you can specify it using the 474 third parameter. Strings that only exceed the length by the tolerance 475 margin given in the fourth parameter will not be truncated. 476 477 .. sourcecode:: jinja 478 479 {{ "foo bar baz qux"|truncate(9) }} 480 -> "foo..." 481 {{ "foo bar baz qux"|truncate(9, True) }} 482 -> "foo ba..." 483 {{ "foo bar baz qux"|truncate(11) }} 484 -> "foo bar baz qux" 485 {{ "foo bar baz qux"|truncate(11, False, '...', 0) }} 486 -> "foo bar..." 487 488 The default leeway on newer Jinja2 versions is 5 and was 0 before but 489 can be reconfigured globally. 490 """ 491 if leeway is None: 492 leeway = env.policies['truncate.leeway'] 493 assert length >= len(end), 'expected length >= %s, got %s' % (len(end), length) 494 assert leeway >= 0, 'expected leeway >= 0, got %s' % leeway 495 if len(s) <= length + leeway: 496 return s 497 if killwords: 498 return s[:length - len(end)] + end 499 result = s[:length - len(end)].rsplit(' ', 1)[0] 500 return result + end 501 502 503@environmentfilter 504def do_wordwrap(environment, s, width=79, break_long_words=True, 505 wrapstring=None): 506 """ 507 Return a copy of the string passed to the filter wrapped after 508 ``79`` characters. You can override this default using the first 509 parameter. If you set the second parameter to `false` Jinja will not 510 split words apart if they are longer than `width`. By default, the newlines 511 will be the default newlines for the environment, but this can be changed 512 using the wrapstring keyword argument. 513 514 .. versionadded:: 2.7 515 Added support for the `wrapstring` parameter. 516 """ 517 if not wrapstring: 518 wrapstring = environment.newline_sequence 519 import textwrap 520 return wrapstring.join(textwrap.wrap(s, width=width, expand_tabs=False, 521 replace_whitespace=False, 522 break_long_words=break_long_words)) 523 524 525def do_wordcount(s): 526 """Count the words in that string.""" 527 return len(_word_re.findall(s)) 528 529 530def do_int(value, default=0, base=10): 531 """Convert the value into an integer. If the 532 conversion doesn't work it will return ``0``. You can 533 override this default using the first parameter. You 534 can also override the default base (10) in the second 535 parameter, which handles input with prefixes such as 536 0b, 0o and 0x for bases 2, 8 and 16 respectively. 537 The base is ignored for decimal numbers and non-string values. 538 """ 539 try: 540 if isinstance(value, string_types): 541 return int(value, base) 542 return int(value) 543 except (TypeError, ValueError): 544 # this quirk is necessary so that "42.23"|int gives 42. 545 try: 546 return int(float(value)) 547 except (TypeError, ValueError): 548 return default 549 550 551def do_float(value, default=0.0): 552 """Convert the value into a floating point number. If the 553 conversion doesn't work it will return ``0.0``. You can 554 override this default using the first parameter. 555 """ 556 try: 557 return float(value) 558 except (TypeError, ValueError): 559 return default 560 561 562def do_format(value, *args, **kwargs): 563 """ 564 Apply python string formatting on an object: 565 566 .. sourcecode:: jinja 567 568 {{ "%s - %s"|format("Hello?", "Foo!") }} 569 -> Hello? - Foo! 570 """ 571 if args and kwargs: 572 raise FilterArgumentError('can\'t handle positional and keyword ' 573 'arguments at the same time') 574 return soft_unicode(value) % (kwargs or args) 575 576 577def do_trim(value): 578 """Strip leading and trailing whitespace.""" 579 return soft_unicode(value).strip() 580 581 582def do_striptags(value): 583 """Strip SGML/XML tags and replace adjacent whitespace by one space. 584 """ 585 if hasattr(value, '__html__'): 586 value = value.__html__() 587 return Markup(text_type(value)).striptags() 588 589 590def do_slice(value, slices, fill_with=None): 591 """Slice an iterator and return a list of lists containing 592 those items. Useful if you want to create a div containing 593 three ul tags that represent columns: 594 595 .. sourcecode:: html+jinja 596 597 <div class="columwrapper"> 598 {%- for column in items|slice(3) %} 599 <ul class="column-{{ loop.index }}"> 600 {%- for item in column %} 601 <li>{{ item }}</li> 602 {%- endfor %} 603 </ul> 604 {%- endfor %} 605 </div> 606 607 If you pass it a second argument it's used to fill missing 608 values on the last iteration. 609 """ 610 seq = list(value) 611 length = len(seq) 612 items_per_slice = length // slices 613 slices_with_extra = length % slices 614 offset = 0 615 for slice_number in range(slices): 616 start = offset + slice_number * items_per_slice 617 if slice_number < slices_with_extra: 618 offset += 1 619 end = offset + (slice_number + 1) * items_per_slice 620 tmp = seq[start:end] 621 if fill_with is not None and slice_number >= slices_with_extra: 622 tmp.append(fill_with) 623 yield tmp 624 625 626def do_batch(value, linecount, fill_with=None): 627 """ 628 A filter that batches items. It works pretty much like `slice` 629 just the other way round. It returns a list of lists with the 630 given number of items. If you provide a second parameter this 631 is used to fill up missing items. See this example: 632 633 .. sourcecode:: html+jinja 634 635 <table> 636 {%- for row in items|batch(3, ' ') %} 637 <tr> 638 {%- for column in row %} 639 <td>{{ column }}</td> 640 {%- endfor %} 641 </tr> 642 {%- endfor %} 643 </table> 644 """ 645 tmp = [] 646 for item in value: 647 if len(tmp) == linecount: 648 yield tmp 649 tmp = [] 650 tmp.append(item) 651 if tmp: 652 if fill_with is not None and len(tmp) < linecount: 653 tmp += [fill_with] * (linecount - len(tmp)) 654 yield tmp 655 656 657def do_round(value, precision=0, method='common'): 658 """Round the number to a given precision. The first 659 parameter specifies the precision (default is ``0``), the 660 second the rounding method: 661 662 - ``'common'`` rounds either up or down 663 - ``'ceil'`` always rounds up 664 - ``'floor'`` always rounds down 665 666 If you don't specify a method ``'common'`` is used. 667 668 .. sourcecode:: jinja 669 670 {{ 42.55|round }} 671 -> 43.0 672 {{ 42.55|round(1, 'floor') }} 673 -> 42.5 674 675 Note that even if rounded to 0 precision, a float is returned. If 676 you need a real integer, pipe it through `int`: 677 678 .. sourcecode:: jinja 679 680 {{ 42.55|round|int }} 681 -> 43 682 """ 683 if not method in ('common', 'ceil', 'floor'): 684 raise FilterArgumentError('method must be common, ceil or floor') 685 if method == 'common': 686 return round(value, precision) 687 func = getattr(math, method) 688 return func(value * (10 ** precision)) / (10 ** precision) 689 690 691# Use a regular tuple repr here. This is what we did in the past and we 692# really want to hide this custom type as much as possible. In particular 693# we do not want to accidentally expose an auto generated repr in case 694# people start to print this out in comments or something similar for 695# debugging. 696_GroupTuple = namedtuple('_GroupTuple', ['grouper', 'list']) 697_GroupTuple.__repr__ = tuple.__repr__ 698_GroupTuple.__str__ = tuple.__str__ 699 700@environmentfilter 701def do_groupby(environment, value, attribute): 702 """Group a sequence of objects by a common attribute. 703 704 If you for example have a list of dicts or objects that represent persons 705 with `gender`, `first_name` and `last_name` attributes and you want to 706 group all users by genders you can do something like the following 707 snippet: 708 709 .. sourcecode:: html+jinja 710 711 <ul> 712 {% for group in persons|groupby('gender') %} 713 <li>{{ group.grouper }}<ul> 714 {% for person in group.list %} 715 <li>{{ person.first_name }} {{ person.last_name }}</li> 716 {% endfor %}</ul></li> 717 {% endfor %} 718 </ul> 719 720 Additionally it's possible to use tuple unpacking for the grouper and 721 list: 722 723 .. sourcecode:: html+jinja 724 725 <ul> 726 {% for grouper, list in persons|groupby('gender') %} 727 ... 728 {% endfor %} 729 </ul> 730 731 As you can see the item we're grouping by is stored in the `grouper` 732 attribute and the `list` contains all the objects that have this grouper 733 in common. 734 735 .. versionchanged:: 2.6 736 It's now possible to use dotted notation to group by the child 737 attribute of another attribute. 738 """ 739 expr = make_attrgetter(environment, attribute) 740 return [_GroupTuple(key, list(values)) for key, values 741 in groupby(sorted(value, key=expr), expr)] 742 743 744@environmentfilter 745def do_sum(environment, iterable, attribute=None, start=0): 746 """Returns the sum of a sequence of numbers plus the value of parameter 747 'start' (which defaults to 0). When the sequence is empty it returns 748 start. 749 750 It is also possible to sum up only certain attributes: 751 752 .. sourcecode:: jinja 753 754 Total: {{ items|sum(attribute='price') }} 755 756 .. versionchanged:: 2.6 757 The `attribute` parameter was added to allow suming up over 758 attributes. Also the `start` parameter was moved on to the right. 759 """ 760 if attribute is not None: 761 iterable = imap(make_attrgetter(environment, attribute), iterable) 762 return sum(iterable, start) 763 764 765def do_list(value): 766 """Convert the value into a list. If it was a string the returned list 767 will be a list of characters. 768 """ 769 return list(value) 770 771 772def do_mark_safe(value): 773 """Mark the value as safe which means that in an environment with automatic 774 escaping enabled this variable will not be escaped. 775 """ 776 return Markup(value) 777 778 779def do_mark_unsafe(value): 780 """Mark a value as unsafe. This is the reverse operation for :func:`safe`.""" 781 return text_type(value) 782 783 784def do_reverse(value): 785 """Reverse the object or return an iterator that iterates over it the other 786 way round. 787 """ 788 if isinstance(value, string_types): 789 return value[::-1] 790 try: 791 return reversed(value) 792 except TypeError: 793 try: 794 rv = list(value) 795 rv.reverse() 796 return rv 797 except TypeError: 798 raise FilterArgumentError('argument must be iterable') 799 800 801@environmentfilter 802def do_attr(environment, obj, name): 803 """Get an attribute of an object. ``foo|attr("bar")`` works like 804 ``foo.bar`` just that always an attribute is returned and items are not 805 looked up. 806 807 See :ref:`Notes on subscriptions <notes-on-subscriptions>` for more details. 808 """ 809 try: 810 name = str(name) 811 except UnicodeError: 812 pass 813 else: 814 try: 815 value = getattr(obj, name) 816 except AttributeError: 817 pass 818 else: 819 if environment.sandboxed and not \ 820 environment.is_safe_attribute(obj, name, value): 821 return environment.unsafe_undefined(obj, name) 822 return value 823 return environment.undefined(obj=obj, name=name) 824 825 826@contextfilter 827def do_map(*args, **kwargs): 828 """Applies a filter on a sequence of objects or looks up an attribute. 829 This is useful when dealing with lists of objects but you are really 830 only interested in a certain value of it. 831 832 The basic usage is mapping on an attribute. Imagine you have a list 833 of users but you are only interested in a list of usernames: 834 835 .. sourcecode:: jinja 836 837 Users on this page: {{ users|map(attribute='username')|join(', ') }} 838 839 Alternatively you can let it invoke a filter by passing the name of the 840 filter and the arguments afterwards. A good example would be applying a 841 text conversion filter on a sequence: 842 843 .. sourcecode:: jinja 844 845 Users on this page: {{ titles|map('lower')|join(', ') }} 846 847 .. versionadded:: 2.7 848 """ 849 seq, func = prepare_map(args, kwargs) 850 if seq: 851 for item in seq: 852 yield func(item) 853 854 855@contextfilter 856def do_select(*args, **kwargs): 857 """Filters a sequence of objects by applying a test to each object, 858 and only selecting the objects with the test succeeding. 859 860 If no test is specified, each object will be evaluated as a boolean. 861 862 Example usage: 863 864 .. sourcecode:: jinja 865 866 {{ numbers|select("odd") }} 867 {{ numbers|select("odd") }} 868 869 .. versionadded:: 2.7 870 """ 871 return select_or_reject(args, kwargs, lambda x: x, False) 872 873 874@contextfilter 875def do_reject(*args, **kwargs): 876 """Filters a sequence of objects by applying a test to each object, 877 and rejecting the objects with the test succeeding. 878 879 If no test is specified, each object will be evaluated as a boolean. 880 881 Example usage: 882 883 .. sourcecode:: jinja 884 885 {{ numbers|reject("odd") }} 886 887 .. versionadded:: 2.7 888 """ 889 return select_or_reject(args, kwargs, lambda x: not x, False) 890 891 892@contextfilter 893def do_selectattr(*args, **kwargs): 894 """Filters a sequence of objects by applying a test to the specified 895 attribute of each object, and only selecting the objects with the 896 test succeeding. 897 898 If no test is specified, the attribute's value will be evaluated as 899 a boolean. 900 901 Example usage: 902 903 .. sourcecode:: jinja 904 905 {{ users|selectattr("is_active") }} 906 {{ users|selectattr("email", "none") }} 907 908 .. versionadded:: 2.7 909 """ 910 return select_or_reject(args, kwargs, lambda x: x, True) 911 912 913@contextfilter 914def do_rejectattr(*args, **kwargs): 915 """Filters a sequence of objects by applying a test to the specified 916 attribute of each object, and rejecting the objects with the test 917 succeeding. 918 919 If no test is specified, the attribute's value will be evaluated as 920 a boolean. 921 922 .. sourcecode:: jinja 923 924 {{ users|rejectattr("is_active") }} 925 {{ users|rejectattr("email", "none") }} 926 927 .. versionadded:: 2.7 928 """ 929 return select_or_reject(args, kwargs, lambda x: not x, True) 930 931 932@evalcontextfilter 933def do_tojson(eval_ctx, value, indent=None): 934 """Dumps a structure to JSON so that it's safe to use in ``<script>`` 935 tags. It accepts the same arguments and returns a JSON string. Note that 936 this is available in templates through the ``|tojson`` filter which will 937 also mark the result as safe. Due to how this function escapes certain 938 characters this is safe even if used outside of ``<script>`` tags. 939 940 The following characters are escaped in strings: 941 942 - ``<`` 943 - ``>`` 944 - ``&`` 945 - ``'`` 946 947 This makes it safe to embed such strings in any place in HTML with the 948 notable exception of double quoted attributes. In that case single 949 quote your attributes or HTML escape it in addition. 950 951 The indent parameter can be used to enable pretty printing. Set it to 952 the number of spaces that the structures should be indented with. 953 954 Note that this filter is for use in HTML contexts only. 955 956 .. versionadded:: 2.9 957 """ 958 policies = eval_ctx.environment.policies 959 dumper = policies['json.dumps_function'] 960 options = policies['json.dumps_kwargs'] 961 if indent is not None: 962 options = dict(options) 963 options['indent'] = indent 964 return htmlsafe_json_dumps(value, dumper=dumper, **options) 965 966 967def prepare_map(args, kwargs): 968 context = args[0] 969 seq = args[1] 970 971 if len(args) == 2 and 'attribute' in kwargs: 972 attribute = kwargs.pop('attribute') 973 if kwargs: 974 raise FilterArgumentError('Unexpected keyword argument %r' % 975 next(iter(kwargs))) 976 func = make_attrgetter(context.environment, attribute) 977 else: 978 try: 979 name = args[2] 980 args = args[3:] 981 except LookupError: 982 raise FilterArgumentError('map requires a filter argument') 983 func = lambda item: context.environment.call_filter( 984 name, item, args, kwargs, context=context) 985 986 return seq, func 987 988 989def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr): 990 context = args[0] 991 seq = args[1] 992 if lookup_attr: 993 try: 994 attr = args[2] 995 except LookupError: 996 raise FilterArgumentError('Missing parameter for attribute name') 997 transfunc = make_attrgetter(context.environment, attr) 998 off = 1 999 else: 1000 off = 0 1001 transfunc = lambda x: x 1002 1003 try: 1004 name = args[2 + off] 1005 args = args[3 + off:] 1006 func = lambda item: context.environment.call_test( 1007 name, item, args, kwargs) 1008 except LookupError: 1009 func = bool 1010 1011 return seq, lambda item: modfunc(func(transfunc(item))) 1012 1013 1014def select_or_reject(args, kwargs, modfunc, lookup_attr): 1015 seq, func = prepare_select_or_reject(args, kwargs, modfunc, lookup_attr) 1016 if seq: 1017 for item in seq: 1018 if func(item): 1019 yield item 1020 1021 1022FILTERS = { 1023 'abs': abs, 1024 'attr': do_attr, 1025 'batch': do_batch, 1026 'capitalize': do_capitalize, 1027 'center': do_center, 1028 'count': len, 1029 'd': do_default, 1030 'default': do_default, 1031 'dictsort': do_dictsort, 1032 'e': escape, 1033 'escape': escape, 1034 'filesizeformat': do_filesizeformat, 1035 'first': do_first, 1036 'float': do_float, 1037 'forceescape': do_forceescape, 1038 'format': do_format, 1039 'groupby': do_groupby, 1040 'indent': do_indent, 1041 'int': do_int, 1042 'join': do_join, 1043 'last': do_last, 1044 'length': len, 1045 'list': do_list, 1046 'lower': do_lower, 1047 'map': do_map, 1048 'pprint': do_pprint, 1049 'random': do_random, 1050 'reject': do_reject, 1051 'rejectattr': do_rejectattr, 1052 'replace': do_replace, 1053 'reverse': do_reverse, 1054 'round': do_round, 1055 'safe': do_mark_safe, 1056 'select': do_select, 1057 'selectattr': do_selectattr, 1058 'slice': do_slice, 1059 'sort': do_sort, 1060 'string': soft_unicode, 1061 'striptags': do_striptags, 1062 'sum': do_sum, 1063 'title': do_title, 1064 'trim': do_trim, 1065 'truncate': do_truncate, 1066 'upper': do_upper, 1067 'urlencode': do_urlencode, 1068 'urlize': do_urlize, 1069 'wordcount': do_wordcount, 1070 'wordwrap': do_wordwrap, 1071 'xmlattr': do_xmlattr, 1072 'tojson': do_tojson, 1073} 1074