- Corrected a long standing issue with operator precedence of math operations
not being what was expected.
- Added support for Python 3.6 async iterators through a new async mode.
+- Added policies for filter defaults and similar things.
+- urlize now sets "rel noopener" by default.
Version 2.8.2
-------------
}
+# default policies
+DEFAULT_POLICIES = {
+ 'urlize.rel': 'noopener',
+ 'urlize.target': None,
+}
+
+
# export all constants
__all__ = tuple(x for x in locals().keys() if x.isupper())
COMMENT_START_STRING, COMMENT_END_STRING, LINE_STATEMENT_PREFIX, \
LINE_COMMENT_PREFIX, TRIM_BLOCKS, NEWLINE_SEQUENCE, \
DEFAULT_FILTERS, DEFAULT_TESTS, DEFAULT_NAMESPACE, \
- KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS
+ DEFAULT_POLICIES, KEEP_TRAILING_NEWLINE, LSTRIP_BLOCKS
from jinja2.lexer import get_lexer, TokenStream
from jinja2.parser import Parser
from jinja2.nodes import EvalContext
self.bytecode_cache = bytecode_cache
self.auto_reload = auto_reload
+ # configurable policies
+ self.policies = DEFAULT_POLICIES.copy()
+
# load extensions
self.extensions = load_extensions(self, extensions)
@evalcontextfilter
def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False,
- target=None):
+ target=None, rel=None):
"""Converts URLs in plain text into clickable links.
If you pass the filter an additional integer it will shorten the urls
.. versionchanged:: 2.8+
The *target* parameter was added.
"""
- rv = urlize(value, trim_url_limit, nofollow, target)
+ policies = eval_ctx.environment.policies
+ rel = set((rel or '').split() or [])
+ if nofollow:
+ rel.add('nofollow')
+ rel.update((policies['urlize.rel'] or '').split())
+ if target is None:
+ target = policies['urlize.target']
+ rel = ' '.join(sorted(rel)) or None
+ rv = urlize(value, trim_url_limit, rel=rel, target=target)
if eval_ctx.autoescape:
rv = Markup(rv)
return rv
return pformat(obj)
-def urlize(text, trim_url_limit=None, nofollow=False, target=None):
+def urlize(text, trim_url_limit=None, rel=None, target=None):
"""Converts any URLs in text into clickable links. Works on http://,
https:// and www. links. Links can have trailing punctuation (periods,
commas, close-parens) and leading punctuation (opening parens) and
and (x[:limit] + (len(x) >=limit and '...'
or '')) or x
words = _word_split_re.split(text_type(escape(text)))
- nofollow_attr = nofollow and ' rel="nofollow"' or ''
- if target is not None and isinstance(target, string_types):
- target_attr = ' target="%s"' % escape(target)
- else:
- target_attr = ''
+ rel_attr = rel and ' rel="%s"' % text_type(escape(rel)) or ''
+ target_attr = target and ' target="%s"' % escape(target) or ''
+
for i, word in enumerate(words):
match = _punctuation_re.match(word)
if match:
middle.endswith('.com')
)):
middle = '<a href="http://%s"%s%s>%s</a>' % (middle,
- nofollow_attr, target_attr, trim_url(middle))
+ rel_attr, target_attr, trim_url(middle))
if middle.startswith('http://') or \
middle.startswith('https://'):
middle = '<a href="%s"%s%s>%s</a>' % (middle,
- nofollow_attr, target_attr, trim_url(middle))
+ rel_attr, target_attr, trim_url(middle))
if '@' in middle and not middle.startswith('www.') and \
not ':' in middle and _simple_email_re.match(middle):
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
def test_urlize(self, env):
tmpl = env.from_string(
'{{ "foo http://www.example.com/ bar"|urlize }}')
- assert tmpl.render() == 'foo <a href="http://www.example.com/">'\
- 'http://www.example.com/</a> bar'
+ assert tmpl.render() == (
+ 'foo <a href="http://www.example.com/" rel="noopener">'
+ 'http://www.example.com/</a> bar'
+ )
+
+ def test_urlize_rel_policy(self):
+ env = Environment()
+ env.policies['urlize.rel'] = None
+ tmpl = env.from_string(
+ '{{ "foo http://www.example.com/ bar"|urlize }}')
+ assert tmpl.render() == (
+ 'foo <a href="http://www.example.com/">'
+ 'http://www.example.com/</a> bar'
+ )
def test_urlize_target_parameter(self, env):
tmpl = env.from_string(
'{{ "foo http://www.example.com/ bar"|urlize(target="_blank") }}'
)
assert tmpl.render() \
- == 'foo <a href="http://www.example.com/" target="_blank">'\
+ == 'foo <a href="http://www.example.com/" rel="noopener" target="_blank">'\
'http://www.example.com/</a> bar'
- tmpl = env.from_string(
- '{{ "foo http://www.example.com/ bar"|urlize(target=42) }}'
- )
- assert tmpl.render() == 'foo <a href="http://www.example.com/">'\
- 'http://www.example.com/</a> bar'
def test_wordcount(self, env):
tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
def test_urlize_filter_escaping(self, env):
tmpl = env.from_string('{{ "http://www.example.org/<foo"|urlize }}')
- assert tmpl.render() == '<a href="http://www.example.org/<foo">'\
+ assert tmpl.render() == '<a href="http://www.example.org/<foo" rel="noopener">'\
'http://www.example.org/<foo</a>'
def test_loop_call_loop(self, env):