]> git.ipfire.org Git - thirdparty/jinja.git/commitdiff
apply black
authorDavid Lord <davidism@gmail.com>
Fri, 10 Jan 2020 15:46:18 +0000 (07:46 -0800)
committerDavid Lord <davidism@gmail.com>
Fri, 10 Jan 2020 15:54:39 +0000 (07:54 -0800)
67 files changed:
docs/cache_extension.py
examples/basic/cycle.py
examples/basic/debugger.py
examples/basic/inheritance.py
examples/basic/test.py
examples/basic/test_filter_and_linestatements.py
examples/basic/test_loop_filter.py
examples/basic/translate.py
examples/bench.py
examples/profile.py
examples/rwbench/djangoext.py
examples/rwbench/rwbench.py
ext/django2jinja/django2jinja.py
ext/django2jinja/example.py
ext/djangojinja2.py
ext/inlinegettext.py
scripts/generate_identifier_pattern.py
scripts/jinja2-debug.py
scripts/make-release.py
src/jinja2/_compat.py
src/jinja2/_identifier.py
src/jinja2/asyncfilters.py
src/jinja2/asyncsupport.py
src/jinja2/bccache.py
src/jinja2/compiler.py
src/jinja2/constants.py
src/jinja2/debug.py
src/jinja2/defaults.py
src/jinja2/environment.py
src/jinja2/exceptions.py
src/jinja2/ext.py
src/jinja2/filters.py
src/jinja2/idtracking.py
src/jinja2/lexer.py
src/jinja2/loaders.py
src/jinja2/meta.py
src/jinja2/nativetypes.py
src/jinja2/nodes.py
src/jinja2/parser.py
src/jinja2/runtime.py
src/jinja2/sandbox.py
src/jinja2/tests.py
src/jinja2/utils.py
src/jinja2/visitor.py
tests/conftest.py
tests/res/templates/mojibake.txt [new file with mode: 0644]
tests/res/templates/variable_encoding.txt [deleted file]
tests/test_api.py
tests/test_async.py
tests/test_asyncfilters.py
tests/test_bytecode_cache.py
tests/test_core_tags.py
tests/test_debug.py
tests/test_ext.py
tests/test_features.py
tests/test_filters.py
tests/test_idtracking.py
tests/test_imports.py
tests/test_inheritance.py
tests/test_lexnparse.py
tests/test_loader.py
tests/test_nativetypes.py
tests/test_regression.py
tests/test_runtime.py
tests/test_security.py
tests/test_tests.py
tests/test_utils.py

index 992b5951c267b6f236a2f7639c2e79c7a2a39335..387cd465790be78c258304c67b24962e949ef73f 100644 (file)
@@ -4,16 +4,13 @@ from jinja2.ext import Extension
 
 class FragmentCacheExtension(Extension):
     # a set of names that trigger the extension.
-    tags = {'cache'}
+    tags = {"cache"}
 
     def __init__(self, environment):
         super(FragmentCacheExtension, self).__init__(environment)
 
         # add the defaults to the environment
-        environment.extend(
-            fragment_cache_prefix='',
-            fragment_cache=None
-        )
+        environment.extend(fragment_cache_prefix="", fragment_cache=None)
 
     def parse(self, parser):
         # the first token is the token that started the tag.  In our case
@@ -27,19 +24,20 @@ class FragmentCacheExtension(Extension):
 
         # if there is a comma, the user provided a timeout.  If not use
         # None as second parameter.
-        if parser.stream.skip_if('comma'):
+        if parser.stream.skip_if("comma"):
             args.append(parser.parse_expression())
         else:
             args.append(nodes.Const(None))
 
         # now we parse the body of the cache block up to `endcache` and
         # drop the needle (which would always be `endcache` in that case)
-        body = parser.parse_statements(['name:endcache'], drop_needle=True)
+        body = parser.parse_statements(["name:endcache"], drop_needle=True)
 
         # now return a `CallBlock` node that calls our _cache_support
         # helper method on this extension.
-        return nodes.CallBlock(self.call_method('_cache_support', args),
-                               [], [], body).set_lineno(lineno)
+        return nodes.CallBlock(
+            self.call_method("_cache_support", args), [], [], body
+        ).set_lineno(lineno)
 
     def _cache_support(self, name, timeout, caller):
         """Helper callback."""
index 63d8a425df78e89622c4a5b60924546c58aecd95..25dcb0b090ec59ebaf6c2515c95617fc135b0ac2 100644 (file)
@@ -2,11 +2,17 @@ from __future__ import print_function
 
 from jinja2 import Environment
 
-env = Environment(line_statement_prefix="#", variable_start_string="${", variable_end_string="}")
-print(env.from_string("""\
+env = Environment(
+    line_statement_prefix="#", variable_start_string="${", variable_end_string="}"
+)
+print(
+    env.from_string(
+        """\
 <ul>
 # for item in range(10)
     <li class="${loop.cycle('odd', 'even')}">${item}</li>
 # endfor
 </ul>\
-""").render())
+"""
+    ).render()
+)
index b74125b00e4882328031af2342a737af8774b6b4..d3c1a60a7ae82a5e928408c314e28cc7504fd618 100644 (file)
@@ -3,6 +3,6 @@ from __future__ import print_function
 from jinja2 import Environment
 from jinja2.loaders import FileSystemLoader
 
-env = Environment(loader=FileSystemLoader('templates'))
-tmpl = env.get_template('broken.html')
+env = Environment(loader=FileSystemLoader("templates"))
+tmpl = env.get_template("broken.html")
 print(tmpl.render(seq=[3, 2, 4, 5, 3, 2, 0, 2, 1]))
index 647f42cd1fed3498020452f10c30c225a647e130..a3073a5e1eb258dba9c74f7f997dfedd4ef58e66 100644 (file)
@@ -3,9 +3,13 @@ from __future__ import print_function
 from jinja2 import Environment
 from jinja2.loaders import DictLoader
 
-env = Environment(loader=DictLoader({
-'a': '''[A[{% block body %}{% endblock %}]]''',
-'b': '''{% extends 'a' %}{% block body %}[B]{% endblock %}''',
-'c': '''{% extends 'b' %}{% block body %}###{{ super() }}###{% endblock %}'''
-}))
-print(env.get_template('c').render())
+env = Environment(
+    loader=DictLoader(
+        {
+            "a": """[A[{% block body %}{% endblock %}]]""",
+            "b": """{% extends 'a' %}{% block body %}[B]{% endblock %}""",
+            "c": """{% extends 'b' %}{% block body %}###{{ super() }}###{% endblock %}""",
+        }
+    )
+)
+print(env.get_template("c").render())
index 04a6adc7729251a9d767dbbd7aed409be76b09d8..80b9d1f052b335629a850fc072f323eeaebcb845 100644 (file)
@@ -3,8 +3,10 @@ from __future__ import print_function
 from jinja2 import Environment
 from jinja2.loaders import DictLoader
 
-env = Environment(loader=DictLoader({
-'child.html': u'''\
+env = Environment(
+    loader=DictLoader(
+        {
+            "child.html": u"""\
 {% extends master_layout or 'master.html' %}
 {% include helpers = 'helpers.html' %}
 {% macro get_the_answer() %}42{% endmacro %}
@@ -13,15 +15,17 @@ env = Environment(loader=DictLoader({
     {{ get_the_answer() }}
     {{ helpers.conspirate() }}
 {% endblock %}
-''',
-'master.html': u'''\
+""",
+            "master.html": u"""\
 <!doctype html>
 <title>{{ title }}</title>
 {% block body %}{% endblock %}
-''',
-'helpers.html': u'''\
+""",
+            "helpers.html": u"""\
 {% macro conspirate() %}23{% endmacro %}
-'''
-}))
+""",
+        }
+    )
+)
 tmpl = env.get_template("child.html")
 print(tmpl.render())
index c18731c1335650ea60f929bebda7c227212a148d..673b67ed76aea84d1b49a4f1a3b0a41ccffec9b3 100644 (file)
@@ -2,8 +2,11 @@ from __future__ import print_function
 
 from jinja2 import Environment
 
-env = Environment(line_statement_prefix='%', variable_start_string="${", variable_end_string="}")
-tmpl = env.from_string("""\
+env = Environment(
+    line_statement_prefix="%", variable_start_string="${", variable_end_string="}"
+)
+tmpl = env.from_string(
+    """\
 % macro foo()
     ${caller(42)}
 % endmacro
@@ -21,5 +24,6 @@ tmpl = env.from_string("""\
       -  ${item}
     % endfor
 % endfilter
-""")
+"""
+)
 print(tmpl.render(seq=range(10)))
index d5b908b8f33f21016ee2f86b262d66acca0243de..39be08d61c2b8eb8cedb4ca109f97cd778d0b374 100644 (file)
@@ -2,12 +2,14 @@ from __future__ import print_function
 
 from jinja2 import Environment
 
-tmpl = Environment().from_string("""\
+tmpl = Environment().from_string(
+    """\
 <ul>
 {%- for item in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] if item % 2 == 0 %}
     <li>{{ loop.index }} / {{ loop.length }}: {{ item }}</li>
 {%- endfor %}
 </ul>
 if condition: {{ 1 if foo else 0 }}
-""")
+"""
+)
 print(tmpl.render(foo=True))
index bbe445a16f344ae841cd852b23af4b596389d1de..fda8f7a1c0d0caf1dfc1440936da1eb96a6db7fb 100644 (file)
@@ -2,15 +2,17 @@ from __future__ import print_function
 
 from jinja2 import Environment
 
-env = Environment(extensions=['jinja2.ext.i18n'])
-env.globals['gettext'] = {
-    'Hello %(user)s!': 'Hallo %(user)s!'
-}.__getitem__
-env.globals['ngettext'] = lambda s, p, n: {
-    '%(count)s user': '%(count)d Benutzer',
-    '%(count)s users': '%(count)d Benutzer'
+env = Environment(extensions=["jinja2.ext.i18n"])
+env.globals["gettext"] = {"Hello %(user)s!": "Hallo %(user)s!"}.__getitem__
+env.globals["ngettext"] = lambda s, p, n: {
+    "%(count)s user": "%(count)d Benutzer",
+    "%(count)s users": "%(count)d Benutzer",
 }[n == 1 and s or p]
-print(env.from_string("""\
+print(
+    env.from_string(
+        """\
 {% trans %}Hello {{ user }}!{% endtrans %}
 {% trans count=users|count %}{{ count }} user{% pluralize %}{{ count }} users{% endtrans %}
-""").render(user="someone", users=[1, 2, 3]))
+"""
+    ).render(user="someone", users=[1, 2, 3])
+)
index 7d988cd94eb99e563c64bc8c539d5f554a0721d0..473928b9c460e34882b3b86fcd71c3ddae7ead64 100644 (file)
@@ -10,15 +10,16 @@ from timeit import Timer
 from jinja2 import Environment as JinjaEnvironment
 
 context = {
-    'page_title': 'mitsuhiko\'s benchmark',
-    'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
+    "page_title": "mitsuhiko's benchmark",
+    "table": [
+        dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10) for x in range(1000)
+    ],
 }
 
 jinja_template = JinjaEnvironment(
-    line_statement_prefix='%',
-    variable_start_string="${",
-    variable_end_string="}"
-).from_string("""\
+    line_statement_prefix="%", variable_start_string="${", variable_end_string="}"
+).from_string(
+    """\
 <!doctype html>
 <html>
   <head>
@@ -50,17 +51,21 @@ jinja_template = JinjaEnvironment(
     </div>
   </body>
 </html>\
-""")
+"""
+)
+
 
 def test_jinja():
     jinja_template.render(context)
 
+
 try:
     from tornado.template import Template
 except ImportError:
     test_tornado = None
 else:
-    tornado_template = Template("""\
+    tornado_template = Template(
+        """\
 <!doctype html>
 <html>
   <head>
@@ -92,19 +97,23 @@ else:
     </div>
   </body>
 </html>\
-""")
+"""
+    )
 
     def test_tornado():
         tornado_template.generate(**context)
 
+
 try:
     from django.conf import settings
+
     settings.configure()
     from django.template import Template as DjangoTemplate, Context as DjangoContext
 except ImportError:
     test_django = None
 else:
-    django_template = DjangoTemplate("""\
+    django_template = DjangoTemplate(
+        """\
 <!doctype html>
 <html>
   <head>
@@ -132,20 +141,26 @@ else:
     </div>
   </body>
 </html>\
-""")
+"""
+    )
 
     def test_django():
         c = DjangoContext(context)
-        c['navigation'] = [('index.html', 'Index'), ('downloads.html', 'Downloads'),
-                           ('products.html', 'Products')]
+        c["navigation"] = [
+            ("index.html", "Index"),
+            ("downloads.html", "Downloads"),
+            ("products.html", "Products"),
+        ]
         django_template.render(c)
 
+
 try:
     from mako.template import Template as MakoTemplate
 except ImportError:
     test_mako = None
 else:
-    mako_template = MakoTemplate("""\
+    mako_template = MakoTemplate(
+        """\
 <!doctype html>
 <html>
   <head>
@@ -173,17 +188,20 @@ else:
     </div>
   </body>
 </html>\
-""")
+"""
+    )
 
     def test_mako():
         mako_template.render(**context)
 
+
 try:
     from genshi.template import MarkupTemplate as GenshiTemplate
 except ImportError:
     test_genshi = None
 else:
-    genshi_template = GenshiTemplate("""\
+    genshi_template = GenshiTemplate(
+        """\
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
   <head>
     <title>${page_title}</title>
@@ -207,17 +225,20 @@ else:
     </div>
   </body>
 </html>\
-""")
+"""
+    )
 
     def test_genshi():
-        genshi_template.generate(**context).render('html', strip_whitespace=False)
+        genshi_template.generate(**context).render("html", strip_whitespace=False)
+
 
 try:
     from Cheetah.Template import Template as CheetahTemplate
 except ImportError:
     test_cheetah = None
 else:
-    cheetah_template = CheetahTemplate("""\
+    cheetah_template = CheetahTemplate(
+        """\
 #import cgi
 <!doctype html>
 <html>
@@ -246,18 +267,22 @@ else:
     </div>
   </body>
 </html>\
-""", searchList=[dict(context)])
+""",
+        searchList=[dict(context)],
+    )
 
     def test_cheetah():
         unicode(cheetah_template)
 
+
 try:
     import tenjin
 except ImportError:
     test_tenjin = None
 else:
     tenjin_template = tenjin.Template()
-    tenjin_template.convert("""\
+    tenjin_template.convert(
+        """\
 <!doctype html>
 <html>
   <head>
@@ -285,19 +310,23 @@ else:
     </div>
   </body>
 </html>\
-""")
+"""
+    )
 
     def test_tenjin():
         from tenjin.helpers import escape, to_str
+
         tenjin_template.render(context, locals())
 
+
 try:
     from spitfire.compiler import util as SpitfireTemplate
     from spitfire.compiler.analyzer import o2_options as spitfire_optimizer
 except ImportError:
     test_spitfire = None
 else:
-    spitfire_template = SpitfireTemplate.load_template("""\
+    spitfire_template = SpitfireTemplate.load_template(
+        """\
 <!doctype html>
 <html>
   <head>
@@ -325,8 +354,12 @@ else:
     </div>
   </body>
 </html>\
-""", 'spitfire_tmpl', spitfire_optimizer, {'enable_filters': False})
-    spitfire_context = dict(context, **{'cgi': cgi})
+""",
+        "spitfire_tmpl",
+        spitfire_optimizer,
+        {"enable_filters": False},
+    )
+    spitfire_context = dict(context, **{"cgi": cgi})
 
     def test_spitfire():
         spitfire_template(search_list=[spitfire_context]).main()
@@ -337,7 +370,8 @@ try:
 except ImportError:
     test_chameleon = None
 else:
-    chameleon_template = PageTemplate("""\
+    chameleon_template = PageTemplate(
+        """\
 <html xmlns:tal="http://xml.zope.org/namespaces/tal">
   <head>
     <title tal:content="page_title">Page Title</title>
@@ -358,23 +392,27 @@ else:
     </div>
   </body>
 </html>\
-""")
+"""
+    )
     chameleon_context = dict(context)
-    chameleon_context['sections'] = [
-        ('index.html', 'Index'),
-        ('downloads.html', 'Downloads'),
-        ('products.html', 'Products')
+    chameleon_context["sections"] = [
+        ("index.html", "Index"),
+        ("downloads.html", "Downloads"),
+        ("products.html", "Products"),
     ]
+
     def test_chameleon():
         chameleon_template.render(**chameleon_context)
 
+
 try:
     from chameleon.zpt.template import PageTemplate
     from chameleon.genshi import language
 except ImportError:
     test_chameleon_genshi = None
 else:
-    chameleon_genshi_template = PageTemplate("""\
+    chameleon_genshi_template = PageTemplate(
+        """\
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:py="http://genshi.edgewall.org/">
   <head>
     <title>${page_title}</title>
@@ -395,40 +433,63 @@ else:
     </div>
   </body>
 </html>\
-""", parser=language.Parser())
+""",
+        parser=language.Parser(),
+    )
     chameleon_genshi_context = dict(context)
-    chameleon_genshi_context['sections'] = [
-        ('index.html', 'Index'),
-        ('downloads.html', 'Downloads'),
-        ('products.html', 'Products')
+    chameleon_genshi_context["sections"] = [
+        ("index.html", "Index"),
+        ("downloads.html", "Downloads"),
+        ("products.html", "Products"),
     ]
+
     def test_chameleon_genshi():
         chameleon_genshi_template.render(**chameleon_genshi_context)
 
 
-sys.stdout.write('\r' + '\n'.join((
-    '=' * 80,
-    'Template Engine BigTable Benchmark'.center(80),
-    '=' * 80,
-    __doc__,
-    '-' * 80
-)) + '\n')
+sys.stdout.write(
+    "\r"
+    + "\n".join(
+        (
+            "=" * 80,
+            "Template Engine BigTable Benchmark".center(80),
+            "=" * 80,
+            __doc__,
+            "-" * 80,
+        )
+    )
+    + "\n"
+)
 
 
-for test in 'jinja', 'mako', 'tornado', 'tenjin', 'spitfire', 'django', 'genshi', 'cheetah', 'chameleon', 'chameleon_genshi':
-    if locals()['test_' + test] is None:
-        sys.stdout.write('    %-20s*not installed*\n' % test)
+for test in (
+    "jinja",
+    "mako",
+    "tornado",
+    "tenjin",
+    "spitfire",
+    "django",
+    "genshi",
+    "cheetah",
+    "chameleon",
+    "chameleon_genshi",
+):
+    if locals()["test_" + test] is None:
+        sys.stdout.write("    %-20s*not installed*\n" % test)
         continue
-    t = Timer(setup='from __main__ import test_%s as bench' % test,
-              stmt='bench()')
-    sys.stdout.write(' >> %-20s<running>' % test)
+    t = Timer(setup="from __main__ import test_%s as bench" % test, stmt="bench()")
+    sys.stdout.write(" >> %-20s<running>" % test)
     sys.stdout.flush()
-    sys.stdout.write('\r    %-20s%.4f seconds\n' % (test, t.timeit(number=50) / 50))
-sys.stdout.write('-' * 80 + '\n')
-sys.stdout.write('''\
+    sys.stdout.write("\r    %-20s%.4f seconds\n" % (test, t.timeit(number=50) / 50))
+sys.stdout.write("-" * 80 + "\n")
+sys.stdout.write(
+    """\
     WARNING: The results of this benchmark are useless to compare the
     performance of template engines and should not be taken seriously in any
     way.  It's testing the performance of simple loops and has no real-world
     usefulnes.  It only used to check if changes on the Jinja code affect
     performance in a good or bad way and how it roughly compares to others.
-''' + '=' * 80 + '\n')
+"""
+    + "=" * 80
+    + "\n"
+)
index e6deb47f63460617ce23f9c4c9f887ab3981db67..b16d99f2a74219c2b3c4db3a0363546967ed3b4c 100644 (file)
@@ -1,4 +1,5 @@
 from __future__ import print_function
+
 try:
     from cProfile import Profile
 except ImportError:
@@ -7,8 +8,10 @@ from pstats import Stats
 from jinja2 import Environment as JinjaEnvironment
 
 context = {
-    'page_title': 'mitsuhiko\'s benchmark',
-    'table': [dict(a=1,b=2,c=3,d=4,e=5,f=6,g=7,h=8,i=9,j=10) for x in range(1000)]
+    "page_title": "mitsuhiko's benchmark",
+    "table": [
+        dict(a=1, b=2, c=3, d=4, e=5, f=6, g=7, h=8, i=9, j=10) for x in range(1000)
+    ],
 }
 
 source = """\
@@ -39,9 +42,7 @@ source = """\
 </html>\
 """
 jinja_template = JinjaEnvironment(
-    line_statement_prefix='%',
-    variable_start_string="${",
-    variable_end_string="}"
+    line_statement_prefix="%", variable_start_string="${", variable_end_string="}"
 ).from_string(source)
 print(jinja_template.environment.compile(source, raw=True))
 
@@ -49,5 +50,5 @@ print(jinja_template.environment.compile(source, raw=True))
 p = Profile()
 p.runcall(lambda: jinja_template.render(context))
 stats = Stats(p)
-stats.sort_stats('time', 'calls')
+stats.sort_stats("time", "calls")
 stats.print_stats()
index 06897e5f8980e7c095430a6e67d36ba9709d796a..0052aefc283d28d8c5beca54199e8e7c4d3e418a 100644 (file)
@@ -12,12 +12,13 @@ from rwbench import dateformat
 from rwbench import ROOT
 
 settings.configure(
-    TEMPLATE_DIRS=(join(ROOT, 'django'),),
+    TEMPLATE_DIRS=(join(ROOT, "django"),),
     TEMPLATE_LOADERS=(
-        ('django.template.loaders.cached.Loader', (
-            'django.template.loaders.filesystem.Loader',
-        )),
-    )
+        (
+            "django.template.loaders.cached.Loader",
+            ("django.template.loaders.filesystem.Loader",),
+        ),
+    ),
 )
 
 # for django extensions.  We monkey patch our extensions in so that
@@ -58,13 +59,12 @@ def form(parser, token):
     args = []
     while p.more():
         args.append(p.value())
-    body = parser.parse(('endform',))
+    body = parser.parse(("endform",))
     parser.delete_first_token()
     return FormNode(body, *args)
 
 
 class InputFieldNode(Node):
-
     def __init__(self, name, type=None, value=None):
         self.name = var_or_none(name)
         self.type = var_or_none(type)
@@ -72,22 +72,17 @@ class InputFieldNode(Node):
 
     def render(self, context):
         name = self.name.resolve(context)
-        type = 'text'
-        value = ''
+        type = "text"
+        value = ""
         if self.type is not None:
             type = self.type.resolve(context)
         if self.value is not None:
             value = self.value.resolve(context)
-        tmpl = django_loader.get_template('_input_field.html')
-        return tmpl.render(DjangoContext({
-            'name':     name,
-            'type':     type,
-            'value':    value
-        }))
+        tmpl = django_loader.get_template("_input_field.html")
+        return tmpl.render(DjangoContext({"name": name, "type": type, "value": value}))
 
 
 class TextareaNode(Node):
-
     def __init__(self, name, rows=None, cols=None, value=None):
         self.name = var_or_none(name)
         self.rows = var_or_none(rows)
@@ -98,24 +93,20 @@ class TextareaNode(Node):
         name = self.name.resolve(context)
         rows = 10
         cols = 40
-        value = ''
+        value = ""
         if self.rows is not None:
             rows = int(self.rows.resolve(context))
         if self.cols is not None:
             cols = int(self.cols.resolve(context))
         if self.value is not None:
             value = self.value.resolve(context)
-        tmpl = django_loader.get_template('_textarea.html')
-        return tmpl.render(DjangoContext({
-            'name':     name,
-            'rows':     rows,
-            'cols':     cols,
-            'value':    value
-        }))
+        tmpl = django_loader.get_template("_textarea.html")
+        return tmpl.render(
+            DjangoContext({"name": name, "rows": rows, "cols": cols, "value": value})
+        )
 
 
 class FormNode(Node):
-
     def __init__(self, body, action=None, method=None):
         self.body = body
         self.action = action
@@ -123,15 +114,13 @@ class FormNode(Node):
 
     def render(self, context):
         body = self.body.render(context)
-        action = ''
-        method = 'post'
+        action = ""
+        method = "post"
         if self.action is not None:
             action = self.action.resolve(context)
         if self.method is not None:
             method = self.method.resolve(context)
-        tmpl = django_loader.get_template('_form.html')
-        return tmpl.render(DjangoContext({
-            'body':     body,
-            'action':   action,
-            'method':   method
-        }))
+        tmpl = django_loader.get_template("_form.html")
+        return tmpl.render(
+            DjangoContext({"body": body, "action": action, "method": method})
+        )
index af5d40bb2143ca5c991e76db84a77bc65c7c5126..957216afb5f0c1a7d67028ee9565dc285b04260a 100644 (file)
@@ -40,20 +40,19 @@ ROOT = abspath(dirname(__file__))
 
 
 def dateformat(x):
-    return x.strftime('%Y-%m-%d')
+    return x.strftime("%Y-%m-%d")
 
 
-jinja_env = Environment(loader=FileSystemLoader(join(ROOT, 'jinja')))
-jinja_env.filters['dateformat'] = dateformat
-mako_lookup = TemplateLookup(directories=[join(ROOT, 'mako')])
-genshi_loader = GenshiTemplateLoader([join(ROOT, 'genshi')])
+jinja_env = Environment(loader=FileSystemLoader(join(ROOT, "jinja")))
+jinja_env.filters["dateformat"] = dateformat
+mako_lookup = TemplateLookup(directories=[join(ROOT, "mako")])
+genshi_loader = GenshiTemplateLoader([join(ROOT, "genshi")])
 
 
 class Article(object):
-
     def __init__(self, id):
         self.id = id
-        self.href = '/article/%d' % self.id
+        self.href = "/article/%d" % self.id
         self.title = generate_lorem_ipsum(1, False, 5, 10)
         self.user = choice(users)
         self.body = generate_lorem_ipsum()
@@ -62,33 +61,33 @@ class Article(object):
 
 
 class User(object):
-
     def __init__(self, username):
-        self.href = '/user/%s' % username
+        self.href = "/user/%s" % username
         self.username = username
 
 
-users = map(User, [u'John Doe', u'Jane Doe', u'Peter Somewhat'])
+users = map(User, [u"John Doe", u"Jane Doe", u"Peter Somewhat"])
 articles = map(Article, range(20))
 navigation = [
-    ('index',           'Index'),
-    ('about',           'About'),
-    ('foo?bar=1',       'Foo with Bar'),
-    ('foo?bar=2&s=x',   'Foo with X'),
-    ('blah',            'Blub Blah'),
-    ('hehe',            'Haha'),
+    ("index", "Index"),
+    ("about", "About"),
+    ("foo?bar=1", "Foo with Bar"),
+    ("foo?bar=2&s=x", "Foo with X"),
+    ("blah", "Blub Blah"),
+    ("hehe", "Haha"),
 ] * 5
 
 context = dict(users=users, articles=articles, page_navigation=navigation)
 
-jinja_template = jinja_env.get_template('index.html')
-mako_template = mako_lookup.get_template('index.html')
-genshi_template = genshi_loader.load('index.html')
+jinja_template = jinja_env.get_template("index.html")
+mako_template = mako_lookup.get_template("index.html")
+genshi_template = genshi_loader.load("index.html")
 
 
 def test_jinja():
     jinja_template.render(context)
 
+
 def test_mako():
     mako_template.render_unicode(**context)
 
@@ -96,27 +95,28 @@ def test_mako():
 def test_django():
     # not cached because django is not thread safe and does
     # not cache by itself so it would be unfair to cache it here.
-    django_template = django_loader.get_template('index.html')
+    django_template = django_loader.get_template("index.html")
     django_template.render(DjangoContext(context))
 
 
 def test_genshi():
-    genshi_template.generate(**context).render('html', doctype='html')
+    genshi_template.generate(**context).render("html", doctype="html")
 
 
-if __name__ == '__main__':
-    sys.stdout.write('Realworldish Benchmark:\n')
-    for test in 'jinja', 'mako', 'django', 'genshi':
-        t = Timer(setup='from __main__ import test_%s as bench' % test,
-                  stmt='bench()')
-        sys.stdout.write(' >> %-20s<running>' % test)
+if __name__ == "__main__":
+    sys.stdout.write("Realworldish Benchmark:\n")
+    for test in "jinja", "mako", "django", "genshi":
+        t = Timer(setup="from __main__ import test_%s as bench" % test, stmt="bench()")
+        sys.stdout.write(" >> %-20s<running>" % test)
         sys.stdout.flush()
-        sys.stdout.write('\r    %-20s%.4f seconds\n' % (test, t.timeit(number=200) / 200))
+        sys.stdout.write(
+            "\r    %-20s%.4f seconds\n" % (test, t.timeit(number=200) / 200)
+        )
 
-    if '-p' in sys.argv:
-        print('Jinja profile')
+    if "-p" in sys.argv:
+        print("Jinja profile")
         p = Profile()
         p.runcall(test_jinja)
         stats = Stats(p)
-        stats.sort_stats('time', 'calls')
+        stats.sort_stats("time", "calls")
         stats.print_stats()
index e9c19b297f07506df92821be81036109108be9b5..25b116e59046a469d77f232bc44a6819da540209 100644 (file)
@@ -92,7 +92,7 @@ from jinja2.defaults import *
 
 _node_handlers = {}
 _resolved_filters = {}
-_newline_re = re.compile(r'(?:\r\n|\r|\n)')
+_newline_re = re.compile(r"(?:\r\n|\r|\n)")
 
 
 # Django stores an itertools object on the cycle node.  Not only is this
@@ -100,9 +100,13 @@ _newline_re = re.compile(r'(?:\r\n|\r|\n)')
 # string values passed to the constructor to create a jinja loop.cycle()
 # call from it.
 _old_cycle_init = core_tags.CycleNode.__init__
+
+
 def _fixed_cycle_init(self, cyclevars, variable_name=None):
     self.raw_cycle_vars = map(Variable, cyclevars)
     _old_cycle_init(self, cyclevars, variable_name)
+
+
 core_tags.CycleNode.__init__ = _fixed_cycle_init
 
 
@@ -110,11 +114,13 @@ def node(cls):
     def proxy(f):
         _node_handlers[cls] = f
         return f
+
     return proxy
 
 
-def convert_templates(output_dir, extensions=('.html', '.txt'), writer=None,
-                      callback=None):
+def convert_templates(
+    output_dir, extensions=(".html", ".txt"), writer=None, callback=None
+):
     """Iterates over all templates in the template dirs configured and
     translates them and writes the new templates into the output directory.
     """
@@ -136,12 +142,13 @@ def convert_templates(output_dir, extensions=('.html', '.txt'), writer=None,
         writer.stream = original
 
     if callback is None:
+
         def callback(template):
             print(template)
 
     for directory in settings.TEMPLATE_DIRS:
         for dirname, _, files in os.walk(directory):
-            dirname = dirname[len(directory) + 1:]
+            dirname = dirname[len(directory) + 1 :]
             for filename in filter_templates(files):
                 source = os.path.normpath(os.path.join(dirname, filename))
                 target = os.path.join(output_dir, dirname, filename)
@@ -149,7 +156,7 @@ def convert_templates(output_dir, extensions=('.html', '.txt'), writer=None,
                 if not os.path.exists(basetarget):
                     os.makedirs(basetarget)
                 callback(source)
-                f = file(target, 'w')
+                f = file(target, "w")
                 try:
                     translate(f, source)
                 finally:
@@ -159,18 +166,22 @@ def convert_templates(output_dir, extensions=('.html', '.txt'), writer=None,
 class Writer(object):
     """The core writer class."""
 
-    def __init__(self, stream=None, error_stream=None,
-                 block_start_string=BLOCK_START_STRING,
-                 block_end_string=BLOCK_END_STRING,
-                 variable_start_string=VARIABLE_START_STRING,
-                 variable_end_string=VARIABLE_END_STRING,
-                 comment_start_string=COMMENT_START_STRING,
-                 comment_end_string=COMMENT_END_STRING,
-                 initial_autoescape=True,
-                 use_jinja_autoescape=False,
-                 custom_node_handlers=None,
-                 var_re=[],
-                 env=None):
+    def __init__(
+        self,
+        stream=None,
+        error_stream=None,
+        block_start_string=BLOCK_START_STRING,
+        block_end_string=BLOCK_END_STRING,
+        variable_start_string=VARIABLE_START_STRING,
+        variable_end_string=VARIABLE_END_STRING,
+        comment_start_string=COMMENT_START_STRING,
+        comment_end_string=COMMENT_END_STRING,
+        initial_autoescape=True,
+        use_jinja_autoescape=False,
+        custom_node_handlers=None,
+        var_re=[],
+        env=None,
+    ):
         if stream is None:
             stream = sys.stdout
         if error_stream is None:
@@ -186,8 +197,7 @@ class Writer(object):
         self.autoescape = initial_autoescape
         self.spaceless = False
         self.use_jinja_autoescape = use_jinja_autoescape
-        self.node_handlers = dict(_node_handlers,
-                                  **(custom_node_handlers or {}))
+        self.node_handlers = dict(_node_handlers, **(custom_node_handlers or {}))
         self._loop_depth = 0
         self._filters_warned = set()
         self.var_re = var_re
@@ -220,15 +230,15 @@ class Writer(object):
 
     def _post_open(self):
         if self.spaceless:
-            self.write('- ')
+            self.write("- ")
         else:
-            self.write(' ')
+            self.write(" ")
 
     def _pre_close(self):
         if self.spaceless:
-            self.write(' -')
+            self.write(" -")
         else:
-            self.write(' ')
+            self.write(" ")
 
     def start_variable(self):
         """Start a variable."""
@@ -237,9 +247,8 @@ class Writer(object):
 
     def end_variable(self, always_safe=False):
         """End a variable."""
-        if not always_safe and self.autoescape and \
-           not self.use_jinja_autoescape:
-            self.write('|e')
+        if not always_safe and self.autoescape and not self.use_jinja_autoescape:
+            self.write("|e")
         self._pre_close()
         self.write(self.variable_end_string)
 
@@ -276,52 +285,50 @@ class Writer(object):
         for filter, args in filters:
             name = self.get_filter_name(filter)
             if name is None:
-                self.warn('Could not find filter %s' % name)
+                self.warn("Could not find filter %s" % name)
                 continue
-            if name not in DEFAULT_FILTERS and \
-               name not in self._filters_warned:
+            if name not in DEFAULT_FILTERS and name not in self._filters_warned:
                 self._filters_warned.add(name)
-                self.warn('Filter %s probably doesn\'t exist in Jinja' %
-                            name)
+                self.warn("Filter %s probably doesn't exist in Jinja" % name)
             if not want_pipe:
                 want_pipe = True
             else:
-                self.write('|')
+                self.write("|")
             self.write(name)
             if args:
-                self.write('(')
+                self.write("(")
                 for idx, (is_var, value) in enumerate(args):
                     if idx:
-                        self.write(', ')
+                        self.write(", ")
                     if is_var:
                         self.node(value)
                     else:
                         self.literal(value)
-                self.write(')')
+                self.write(")")
 
     def get_location(self, origin, position):
         """Returns the location for an origin and position tuple as name
         and lineno.
         """
-        if hasattr(origin, 'source'):
+        if hasattr(origin, "source"):
             source = origin.source
-            name = '<unknown source>'
+            name = "<unknown source>"
         else:
             source = origin.loader(origin.loadname, origin.dirs)[0]
             name = origin.loadname
-        lineno = len(_newline_re.findall(source[:position[0]])) + 1
+        lineno = len(_newline_re.findall(source[: position[0]])) + 1
         return name, lineno
 
     def warn(self, message, node=None):
         """Prints a warning to the error stream."""
-        if node is not None and hasattr(node, 'source'):
+        if node is not None and hasattr(node, "source"):
             filename, lineno = self.get_location(*node.source)
-            message = '[%s:%d] %s' % (filename, lineno, message)
+            message = "[%s:%d] %s" % (filename, lineno, message)
         print(message, file=self.error_stream)
 
     def translate_variable_name(self, var):
         """Performs variable name translation."""
-        if self.in_loop and var == 'forloop' or var.startswith('forloop.'):
+        if self.in_loop and var == "forloop" or var.startswith("forloop."):
             var = var[3:]
 
         for reg, rep, unless in self.var_re:
@@ -348,10 +355,11 @@ class Writer(object):
                 handler(self, node)
                 break
         else:
-            self.warn('Untranslatable node %s.%s found' % (
-                node.__module__,
-                node.__class__.__name__
-            ), node)
+            self.warn(
+                "Untranslatable node %s.%s found"
+                % (node.__module__, node.__class__.__name__),
+                node,
+            )
 
     def body(self, nodes):
         """Calls node() for every node in the iterable passed."""
@@ -367,22 +375,24 @@ def text_node(writer, node):
 @node(Variable)
 def variable(writer, node):
     if node.translate:
-        writer.warn('i18n system used, make sure to install translations', node)
-        writer.write('_(')
+        writer.warn("i18n system used, make sure to install translations", node)
+        writer.write("_(")
     if node.literal is not None:
         writer.literal(node.literal)
     else:
         writer.variable(node.var)
     if node.translate:
-        writer.write(')')
+        writer.write(")")
 
 
 @node(VariableNode)
 def variable_node(writer, node):
     writer.start_variable()
-    if node.filter_expression.var.var == 'block.super' \
-       and not node.filter_expression.filters:
-        writer.write('super()')
+    if (
+        node.filter_expression.var.var == "block.super"
+        and not node.filter_expression.filters
+    ):
+        writer.write("super()")
     else:
         writer.node(node.filter_expression)
     writer.end_variable()
@@ -401,86 +411,89 @@ def comment_tag(writer, node):
 
 @node(core_tags.DebugNode)
 def comment_tag(writer, node):
-    writer.warn('Debug tag detected.  Make sure to add a global function '
-                'called debug to the namespace.', node=node)
-    writer.print_expr('debug()')
+    writer.warn(
+        "Debug tag detected.  Make sure to add a global function "
+        "called debug to the namespace.",
+        node=node,
+    )
+    writer.print_expr("debug()")
 
 
 @node(core_tags.ForNode)
 def for_loop(writer, node):
     writer.start_block()
-    writer.write('for ')
+    writer.write("for ")
     for idx, var in enumerate(node.loopvars):
         if idx:
-            writer.write(', ')
+            writer.write(", ")
         writer.variable(var)
-    writer.write(' in ')
+    writer.write(" in ")
     if node.is_reversed:
-        writer.write('(')
+        writer.write("(")
     writer.node(node.sequence)
     if node.is_reversed:
-        writer.write(')|reverse')
+        writer.write(")|reverse")
     writer.end_block()
     writer.enter_loop()
     writer.body(node.nodelist_loop)
     writer.leave_loop()
-    writer.tag('endfor')
+    writer.tag("endfor")
 
 
 @node(core_tags.IfNode)
 def if_condition(writer, node):
     writer.start_block()
-    writer.write('if ')
-    join_with = 'and'
+    writer.write("if ")
+    join_with = "and"
     if node.link_type == core_tags.IfNode.LinkTypes.or_:
-        join_with = 'or'
+        join_with = "or"
 
     for idx, (ifnot, expr) in enumerate(node.bool_exprs):
         if idx:
-            writer.write(' %s ' % join_with)
+            writer.write(" %s " % join_with)
         if ifnot:
-            writer.write('not ')
+            writer.write("not ")
         writer.node(expr)
     writer.end_block()
     writer.body(node.nodelist_true)
     if node.nodelist_false:
-        writer.tag('else')
+        writer.tag("else")
         writer.body(node.nodelist_false)
-    writer.tag('endif')
+    writer.tag("endif")
 
 
 @node(core_tags.IfEqualNode)
 def if_equal(writer, node):
     writer.start_block()
-    writer.write('if ')
+    writer.write("if ")
     writer.node(node.var1)
     if node.negate:
-        writer.write(' != ')
+        writer.write(" != ")
     else:
-        writer.write(' == ')
+        writer.write(" == ")
     writer.node(node.var2)
     writer.end_block()
     writer.body(node.nodelist_true)
     if node.nodelist_false:
-        writer.tag('else')
+        writer.tag("else")
         writer.body(node.nodelist_false)
-    writer.tag('endif')
+    writer.tag("endif")
 
 
 @node(loader_tags.BlockNode)
 def block(writer, node):
-    writer.tag('block ' + node.name.replace('-', '_').rstrip('_'))
+    writer.tag("block " + node.name.replace("-", "_").rstrip("_"))
     node = node
     while node.parent is not None:
         node = node.parent
     writer.body(node.nodelist)
-    writer.tag('endblock')
+    writer.tag("endblock")
 
 
 @node(loader_tags.ExtendsNode)
 def extends(writer, node):
     writer.start_block()
-    writer.write('extends ')
+    writer.write("extends ")
     if node.parent_name_expr:
         writer.node(node.parent_name_expr)
     else:
@@ -493,8 +506,8 @@ def extends(writer, node):
 @node(loader_tags.IncludeNode)
 def include(writer, node):
     writer.start_block()
-    writer.write('include ')
-    if hasattr(node, 'template'):
+    writer.write("include ")
+    if hasattr(node, "template"):
         writer.literal(node.template.name)
     else:
         writer.node(node.template_name)
@@ -504,19 +517,19 @@ def include(writer, node):
 @node(core_tags.CycleNode)
 def cycle(writer, node):
     if not writer.in_loop:
-        writer.warn('Untranslatable free cycle (cycle outside loop)', node=node)
+        writer.warn("Untranslatable free cycle (cycle outside loop)", node=node)
         return
     if node.variable_name is not None:
         writer.start_block()
-        writer.write('set %s = ' % node.variable_name)
+        writer.write("set %s = " % node.variable_name)
     else:
         writer.start_variable()
-    writer.write('loop.cycle(')
+    writer.write("loop.cycle(")
     for idx, var in enumerate(node.raw_cycle_vars):
         if idx:
-            writer.write(', ')
+            writer.write(", ")
         writer.node(var)
-    writer.write(')')
+    writer.write(")")
     if node.variable_name is not None:
         writer.end_block()
     else:
@@ -526,11 +539,11 @@ def cycle(writer, node):
 @node(core_tags.FilterNode)
 def filter(writer, node):
     writer.start_block()
-    writer.write('filter ')
+    writer.write("filter ")
     writer.filters(node.filter_expr.filters, True)
     writer.end_block()
     writer.body(node.nodelist)
-    writer.tag('endfilter')
+    writer.tag("endfilter")
 
 
 @node(core_tags.AutoEscapeControlNode)
@@ -545,7 +558,7 @@ def autoescape_control(writer, node):
 def spaceless(writer, node):
     original = writer.spaceless
     writer.spaceless = True
-    writer.warn('entering spaceless mode with different semantics', node)
+    writer.warn("entering spaceless mode with different semantics", node)
     # do the initial stripping
     nodelist = list(node.nodelist)
     if nodelist:
@@ -560,14 +573,14 @@ def spaceless(writer, node):
 @node(core_tags.TemplateTagNode)
 def template_tag(writer, node):
     tag = {
-        'openblock':            writer.block_start_string,
-        'closeblock':           writer.block_end_string,
-        'openvariable':         writer.variable_start_string,
-        'closevariable':        writer.variable_end_string,
-        'opencomment':          writer.comment_start_string,
-        'closecomment':         writer.comment_end_string,
-        'openbrace':            '{',
-        'closebrace':           '}'
+        "openblock": writer.block_start_string,
+        "closeblock": writer.block_end_string,
+        "openvariable": writer.variable_start_string,
+        "closevariable": writer.variable_end_string,
+        "opencomment": writer.comment_start_string,
+        "closecomment": writer.comment_end_string,
+        "openbrace": "{",
+        "closebrace": "}",
     }.get(node.tagtype)
     if tag:
         writer.start_variable()
@@ -577,23 +590,22 @@ def template_tag(writer, node):
 
 @node(core_tags.URLNode)
 def url_tag(writer, node):
-    writer.warn('url node used.  make sure to provide a proper url() '
-                'function', node)
+    writer.warn("url node used.  make sure to provide a proper url() function", node)
     if node.asvar:
         writer.start_block()
-        writer.write('set %s = ' % node.asvar)
+        writer.write("set %s = " % node.asvar)
     else:
         writer.start_variable()
     autoescape = writer.autoescape
-    writer.write('url(')
+    writer.write("url(")
     writer.literal(node.view_name)
     for arg in node.args:
-        writer.write(', ')
+        writer.write(", ")
         writer.node(arg)
     for key, arg in node.kwargs.items():
-        writer.write(', %s=' % key)
+        writer.write(", %s=" % key)
         writer.node(arg)
-    writer.write(')')
+    writer.write(")")
     if node.asvar:
         writer.end_block()
     else:
@@ -602,25 +614,31 @@ def url_tag(writer, node):
 
 @node(core_tags.WidthRatioNode)
 def width_ratio(writer, node):
-    writer.warn('widthratio expanded into formula.  You may want to provide '
-                'a helper function for this calculation', node)
+    writer.warn(
+        "widthratio expanded into formula.  You may want to provide "
+        "a helper function for this calculation",
+        node,
+    )
     writer.start_variable()
-    writer.write('(')
+    writer.write("(")
     writer.node(node.val_expr)
-    writer.write(' / ')
+    writer.write(" / ")
     writer.node(node.max_expr)
-    writer.write(' * ')
+    writer.write(" * ")
     writer.write(str(int(node.max_width)))
-    writer.write(')|round|int')
+    writer.write(")|round|int")
     writer.end_variable(always_safe=True)
 
 
 @node(core_tags.WithNode)
 def with_block(writer, node):
-    writer.warn('with block expanded into set statement.  This could cause '
-                'variables following that block to be overridden.', node)
+    writer.warn(
+        "with block expanded into set statement.  This could cause "
+        "variables following that block to be overridden.",
+        node,
+    )
     writer.start_block()
-    writer.write('set %s = ' % node.name)
+    writer.write("set %s = " % node.name)
     writer.node(node.var)
     writer.end_block()
     writer.body(node.nodelist)
@@ -629,55 +647,67 @@ def with_block(writer, node):
 @node(core_tags.RegroupNode)
 def regroup(writer, node):
     if node.expression.var.literal:
-        writer.warn('literal in groupby filter used.   Behavior in that '
-                    'situation is undefined and translation is skipped.', node)
+        writer.warn(
+            "literal in groupby filter used.   Behavior in that "
+            "situation is undefined and translation is skipped.",
+            node,
+        )
         return
     elif node.expression.filters:
-        writer.warn('filters in groupby filter used.   Behavior in that '
-                    'situation is undefined which is most likely a bug '
-                    'in your code.  Filters were ignored.', node)
+        writer.warn(
+            "filters in groupby filter used.   Behavior in that "
+            "situation is undefined which is most likely a bug "
+            "in your code.  Filters were ignored.",
+            node,
+        )
     writer.start_block()
-    writer.write('set %s = ' % node.var_name)
+    writer.write("set %s = " % node.var_name)
     writer.node(node.target)
-    writer.write('|groupby(')
+    writer.write("|groupby(")
     writer.literal(node.expression.var.var)
-    writer.write(')')
+    writer.write(")")
     writer.end_block()
 
 
 @node(core_tags.LoadNode)
 def warn_load(writer, node):
-    writer.warn('load statement used which was ignored on conversion', node)
+    writer.warn("load statement used which was ignored on conversion", node)
 
 
 @node(i18n_tags.GetAvailableLanguagesNode)
 def get_available_languages(writer, node):
-    writer.warn('make sure to provide a get_available_languages function', node)
-    writer.tag('set %s = get_available_languages()' %
-               writer.translate_variable_name(node.variable))
+    writer.warn("make sure to provide a get_available_languages function", node)
+    writer.tag(
+        "set %s = get_available_languages()"
+        % writer.translate_variable_name(node.variable)
+    )
 
 
 @node(i18n_tags.GetCurrentLanguageNode)
 def get_current_language(writer, node):
-    writer.warn('make sure to provide a get_current_language function', node)
-    writer.tag('set %s = get_current_language()' %
-               writer.translate_variable_name(node.variable))
+    writer.warn("make sure to provide a get_current_language function", node)
+    writer.tag(
+        "set %s = get_current_language()"
+        % writer.translate_variable_name(node.variable)
+    )
 
 
 @node(i18n_tags.GetCurrentLanguageBidiNode)
 def get_current_language_bidi(writer, node):
-    writer.warn('make sure to provide a get_current_language_bidi function', node)
-    writer.tag('set %s = get_current_language_bidi()' %
-               writer.translate_variable_name(node.variable))
+    writer.warn("make sure to provide a get_current_language_bidi function", node)
+    writer.tag(
+        "set %s = get_current_language_bidi()"
+        % writer.translate_variable_name(node.variable)
+    )
 
 
 @node(i18n_tags.TranslateNode)
 def simple_gettext(writer, node):
-    writer.warn('i18n system used, make sure to install translations', node)
+    writer.warn("i18n system used, make sure to install translations", node)
     writer.start_variable()
-    writer.write('_(')
+    writer.write("_(")
     writer.node(node.value)
-    writer.write(')')
+    writer.write(")")
     writer.end_variable()
 
 
@@ -699,14 +729,14 @@ def translate_block(writer, node):
                 writer.print_expr(token.contents)
                 touch_var(token.contents)
 
-    writer.warn('i18n system used, make sure to install translations', node)
+    writer.warn("i18n system used, make sure to install translations", node)
     writer.start_block()
-    writer.write('trans')
+    writer.write("trans")
     idx = -1
     for idx, (key, var) in enumerate(node.extra_context.items()):
         if idx:
-            writer.write(',')
-        writer.write(' %s=' % key)
+            writer.write(",")
+        writer.write(" %s=" % key)
         touch_var(key)
         writer.node(var.filter_expression)
 
@@ -717,61 +747,64 @@ def translate_block(writer, node):
         plural_var = node.countervar
         if plural_var not in variables:
             if idx > -1:
-                writer.write(',')
+                writer.write(",")
             touch_var(plural_var)
-            writer.write(' %s=' % plural_var)
+            writer.write(" %s=" % plural_var)
             writer.node(node.counter)
 
     writer.end_block()
     dump_token_list(node.singular)
     if node.plural and node.countervar and node.counter:
         writer.start_block()
-        writer.write('pluralize')
+        writer.write("pluralize")
         if node.countervar != first_var[0]:
-            writer.write(' ' + node.countervar)
+            writer.write(" " + node.countervar)
         writer.end_block()
         dump_token_list(node.plural)
-    writer.tag('endtrans')
+    writer.tag("endtrans")
+
 
 @node("SimpleNode")
 def simple_tag(writer, node):
     """Check if the simple tag exist as a filter in """
     name = node.tag_name
-    if writer.env and \
-       name not in writer.env.filters and \
-       name not in writer._filters_warned:
+    if (
+        writer.env
+        and name not in writer.env.filters
+        and name not in writer._filters_warned
+    ):
         writer._filters_warned.add(name)
-        writer.warn('Filter %s probably doesn\'t exist in Jinja' %
-                    name)
+        writer.warn("Filter %s probably doesn't exist in Jinja" % name)
 
     if not node.vars_to_resolve:
         # No argument, pass the request
         writer.start_variable()
-        writer.write('request|')
+        writer.write("request|")
         writer.write(name)
         writer.end_variable()
         return
 
-    first_var =  node.vars_to_resolve[0]
+    first_var = node.vars_to_resolve[0]
     args = node.vars_to_resolve[1:]
     writer.start_variable()
 
     # Copied from Writer.filters()
     writer.node(first_var)
 
-    writer.write('|')
+    writer.write("|")
     writer.write(name)
     if args:
-        writer.write('(')
+        writer.write("(")
         for idx, var in enumerate(args):
             if idx:
-                writer.write(', ')
+                writer.write(", ")
             if var.var:
                 writer.node(var)
             else:
                 writer.literal(var.literal)
-        writer.write(')')
+        writer.write(")")
     writer.end_variable()
 
+
 # get rid of node now, it shouldn't be used normally
 del node
index 2d4ab9add849a874fe5b6620966848b563bacfc2..9bd6b97d87fa643c91621775ea4b0366321f370c 100644 (file)
@@ -1,7 +1,8 @@
 from django.conf import settings
-settings.configure(TEMPLATE_DIRS=['templates'], TEMPLATE_DEBUG=True)
+
+settings.configure(TEMPLATE_DIRS=["templates"], TEMPLATE_DEBUG=True)
 
 from django2jinja import convert_templates, Writer
 
 writer = Writer(use_jinja_autoescape=True)
-convert_templates('converted', writer=writer)
+convert_templates("converted", writer=writer)
index 3c0c4256d2ad5ebb89b6d97aedbb894edccc3612..48c7cf6a245a92c8782ed0bf067faab2458a5c06 100644 (file)
@@ -45,10 +45,12 @@ def get_env():
 def create_env():
     """Create a new Jinja environment."""
     searchpath = list(settings.JINJA2_TEMPLATE_DIRS)
-    return Environment(loader=FileSystemLoader(searchpath),
-                       auto_reload=settings.TEMPLATE_DEBUG,
-                       cache_size=getattr(settings, 'JINJA2_CACHE_SIZE', 400),
-                       extensions=getattr(settings, 'JINJA2_EXTENSIONS', ()))
+    return Environment(
+        loader=FileSystemLoader(searchpath),
+        auto_reload=settings.TEMPLATE_DEBUG,
+        cache_size=getattr(settings, "JINJA2_CACHE_SIZE", 400),
+        extensions=getattr(settings, "JINJA2_EXTENSIONS", ()),
+    )
 
 
 def get_template(template_name, globals=None):
@@ -67,22 +69,23 @@ def select_template(templates, globals=None):
             return env.get_template(template, globals=globals)
         except TemplateNotFound:
             continue
-    raise TemplateDoesNotExist(', '.join(templates))
+    raise TemplateDoesNotExist(", ".join(templates))
 
 
-def render_to_string(template_name, context=None, request=None,
-                     processors=None):
+def render_to_string(template_name, context=None, request=None, processors=None):
     """Render a template into a string."""
     context = dict(context or {})
     if request is not None:
-        context['request'] = request
+        context["request"] = request
         for processor in chain(get_standard_processors(), processors or ()):
             context.update(processor(request))
     return get_template(template_name).render(context)
 
 
-def render_to_response(template_name, context=None, request=None,
-                       processors=None, mimetype=None):
+def render_to_response(
+    template_name, context=None, request=None, processors=None, mimetype=None
+):
     """Render a template into a response object."""
-    return HttpResponse(render_to_string(template_name, context, request,
-                                         processors), mimetype=mimetype)
+    return HttpResponse(
+        render_to_string(template_name, context, request, processors), mimetype=mimetype
+    )
index fd545b756b96252c2adeeda472c91ccef15fc47d..50a06711eb67c5295a06797967fa9e31f5180bca 100644 (file)
@@ -17,8 +17,8 @@ from jinja2.lexer import count_newlines
 from jinja2.lexer import Token
 
 
-_outside_re = re.compile(r'\\?(gettext|_)\(')
-_inside_re = re.compile(r'\\?[()]')
+_outside_re = re.compile(r"\\?(gettext|_)\(")
+_inside_re = re.compile(r"\\?[()]")
 
 
 class InlineGettext(Extension):
@@ -34,7 +34,7 @@ class InlineGettext(Extension):
         paren_stack = 0
 
         for token in stream:
-            if token.type != 'data':
+            if token.type != "data":
                 yield token
                 continue
 
@@ -51,30 +51,33 @@ class InlineGettext(Extension):
                 new_pos = match.start()
                 if new_pos > pos:
                     preval = token.value[pos:new_pos]
-                    yield Token(lineno, 'data', preval)
+                    yield Token(lineno, "data", preval)
                     lineno += count_newlines(preval)
                 gtok = match.group()
-                if gtok[0] == '\\':
-                    yield Token(lineno, 'data', gtok[1:])
+                if gtok[0] == "\\":
+                    yield Token(lineno, "data", gtok[1:])
                 elif not paren_stack:
-                    yield Token(lineno, 'block_begin', None)
-                    yield Token(lineno, 'name', 'trans')
-                    yield Token(lineno, 'block_end', None)
+                    yield Token(lineno, "block_begin", None)
+                    yield Token(lineno, "name", "trans")
+                    yield Token(lineno, "block_end", None)
                     paren_stack = 1
                 else:
-                    if gtok == '(' or paren_stack > 1:
-                        yield Token(lineno, 'data', gtok)
-                    paren_stack += gtok == ')' and -1 or 1
+                    if gtok == "(" or paren_stack > 1:
+                        yield Token(lineno, "data", gtok)
+                    paren_stack += gtok == ")" and -1 or 1
                     if not paren_stack:
-                        yield Token(lineno, 'block_begin', None)
-                        yield Token(lineno, 'name', 'endtrans')
-                        yield Token(lineno, 'block_end', None)
+                        yield Token(lineno, "block_begin", None)
+                        yield Token(lineno, "name", "endtrans")
+                        yield Token(lineno, "block_end", None)
                 pos = match.end()
 
             if pos < len(token.value):
-                yield Token(lineno, 'data', token.value[pos:])
+                yield Token(lineno, "data", token.value[pos:])
 
         if paren_stack:
-            raise TemplateSyntaxError('unclosed gettext expression',
-                                      token.lineno, stream.name,
-                                      stream.filename)
+            raise TemplateSyntaxError(
+                "unclosed gettext expression",
+                token.lineno,
+                stream.name,
+                stream.filename,
+            )
index 7db5f4a438b39ce71ceb67654796aae35b87d300..96fedba6a8161c8170b63e599cd36783ccfd0709 100755 (executable)
@@ -5,7 +5,7 @@ import re
 import sys
 
 if sys.version_info[0] < 3:
-    raise RuntimeError('This needs to run on Python 3.')
+    raise RuntimeError("This needs to run on Python 3.")
 
 
 def get_characters():
@@ -23,7 +23,7 @@ def get_characters():
     for cp in range(sys.maxunicode + 1):
         s = chr(cp)
 
-        if ('a' + s).isidentifier() and not re.match(r'\w', s):
+        if ("a" + s).isidentifier() and not re.match(r"\w", s):
             yield s
 
 
@@ -33,10 +33,7 @@ def collapse_ranges(data):
 
     Source: https://stackoverflow.com/a/4629241/400617
     """
-    for a, b in itertools.groupby(
-        enumerate(data),
-        lambda x: ord(x[1]) - x[0]
-    ):
+    for a, b in itertools.groupby(enumerate(data), lambda x: ord(x[1]) - x[0]):
         b = list(b)
         yield b[0][1], b[-1][1]
 
@@ -55,23 +52,23 @@ def build_pattern(ranges):
             out.append(a)
             out.append(b)
         else:
-            out.append(f'{a}-{b}')
+            out.append("{}-{}".format(a, b))
 
-    return ''.join(out)
+    return "".join(out)
 
 
 def main():
     """Build the regex pattern and write it to the file
     :file:`jinja2/_identifier.py`."""
     pattern = build_pattern(collapse_ranges(get_characters()))
-    filename = os.path.abspath(os.path.join(
-        os.path.dirname(__file__), '..', 'jinja2', '_identifier.py'
-    ))
+    filename = os.path.abspath(
+        os.path.join(os.path.dirname(__file__), "..", "src", "jinja2", "_identifier.py")
+    )
 
-    with open(filename, 'w', encoding='utf8') as f:
-        f.write('# generated by scripts/generate_identifier_pattern.py\n')
-        f.write(f'pattern = \'{pattern}\'\n')
+    with open(filename, "w", encoding="utf8") as f:
+        f.write("# generated by scripts/generate_identifier_pattern.py\n")
+        f.write('pattern = "{}"\n'.format(pattern))
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
index 4f04436c7dc3b8a0f8f151a8d95056b6008f3eb5..96628ddd66db38683963b987a6b4ea7efafae4c8 100755 (executable)
@@ -17,21 +17,23 @@ from werkzeug import script
 
 import jinja2
 
-env = jinja2.Environment(extensions=['jinja2.ext.i18n', 'jinja2.ext.do',
-                                     'jinja2.ext.loopcontrols',
-                                     'jinja2.ext.with_',
-                                     'jinja2.ext.autoescape'],
-                         autoescape=True)
+env = jinja2.Environment(
+    extensions=[
+        "jinja2.ext.i18n",
+        "jinja2.ext.do",
+        "jinja2.ext.loopcontrols",
+        "jinja2.ext.with_",
+        "jinja2.ext.autoescape",
+    ],
+    autoescape=True,
+)
+
 
 def shell_init_func():
     def _compile(x):
         print(env.compile(x, raw=True))
-    result = {
-        'e':        env,
-        'c':        _compile,
-        't':        env.from_string,
-        'p':        env.parse
-    }
+
+    result = {"e": env, "c": _compile, "t": env.from_string, "p": env.parse}
     for key in jinja2.__all__:
         result[key] = getattr(jinja2, key)
     return result
@@ -40,8 +42,9 @@ def shell_init_func():
 def action_compile():
     print(env.compile(sys.stdin.read(), raw=True))
 
+
 action_shell = script.make_shell(shell_init_func)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     script.run()
index 0b158dd77796b32a7180b1b63bbee3d09d66cace..cd6ce23dbd179f3456932e89415a49f1033b195f 100644 (file)
@@ -20,21 +20,21 @@ from datetime import datetime
 from subprocess import PIPE
 from subprocess import Popen
 
-_date_strip_re = re.compile(r'(?<=\d)(st|nd|rd|th)')
+_date_strip_re = re.compile(r"(?<=\d)(st|nd|rd|th)")
 
 
 def parse_changelog():
-    with open('CHANGES.rst') as f:
+    with open("CHANGES.rst") as f:
         lineiter = iter(f)
         for line in lineiter:
-            match = re.search('^Version\s+(.*)', line.strip())
+            match = re.search("^Version\s+(.*)", line.strip())
 
             if match is None:
                 continue
 
             version = match.group(1).strip()
 
-            if next(lineiter).count('-') != len(match.group(0)):
+            if next(lineiter).count("-") != len(match.group(0)):
                 continue
 
             while 1:
@@ -44,8 +44,8 @@ def parse_changelog():
                     break
 
             match = re.search(
-                r'(?:codename (.*),\s*)?released on (\w+\s+\d+\w+\s+\d+)(?i)',
-                change_info
+                r"(?:codename (.*),\s*)?released on (\w+\s+\d+\w+\s+\d+)(?i)",
+                change_info,
             )
 
             if match is None:
@@ -57,17 +57,17 @@ def parse_changelog():
 
 def bump_version(version):
     try:
-        parts = [int(i) for i in version.split('.')]
+        parts = [int(i) for i in version.split(".")]
     except ValueError:
-        fail('Current version is not numeric')
+        fail("Current version is not numeric")
 
     parts[-1] += 1
-    return '.'.join(map(str, parts))
+    return ".".join(map(str, parts))
 
 
 def parse_date(string):
-    string = _date_strip_re.sub('', string)
-    return datetime.strptime(string, '%B %d %Y')
+    string = _date_strip_re.sub("", string)
+    return datetime.strptime(string, "%B %d %Y")
 
 
 def set_filename_version(filename, version_number, pattern):
@@ -80,34 +80,33 @@ def set_filename_version(filename, version_number, pattern):
 
     with open(filename) as f:
         contents = re.sub(
-            r"^(\s*%s\s*=\s*')(.+?)(')(?sm)" % pattern,
-            inject_version, f.read()
+            r"^(\s*%s\s*=\s*')(.+?)(')(?sm)" % pattern, inject_version, f.read()
         )
 
     if not changed:
-        fail('Could not find %s in %s', pattern, filename)
+        fail("Could not find %s in %s", pattern, filename)
 
-    with open(filename, 'w') as f:
+    with open(filename, "w") as f:
         f.write(contents)
 
 
 def set_init_version(version):
-    info('Setting __init__.py version to %s', version)
-    set_filename_version('jinja2/__init__.py', version, '__version__')
+    info("Setting __init__.py version to %s", version)
+    set_filename_version("jinja2/__init__.py", version, "__version__")
 
 
 def set_setup_version(version):
-    info('Setting setup.py version to %s', version)
-    set_filename_version('setup.py', version, 'version')
+    info("Setting setup.py version to %s", version)
+    set_filename_version("setup.py", version, "version")
 
 
 def build_and_upload():
-    cmd = [sys.executable, 'setup.py', 'sdist', 'bdist_wheel']
+    cmd = [sys.executable, "setup.py", "sdist", "bdist_wheel"]
     Popen(cmd).wait()
 
 
 def fail(message, *args):
-    print('Error:', message % args, file=sys.stderr)
+    print("Error:", message % args, file=sys.stderr)
     sys.exit(1)
 
 
@@ -116,39 +115,39 @@ def info(message, *args):
 
 
 def get_git_tags():
-    return set(
-        Popen(['git', 'tag'], stdout=PIPE).communicate()[0].splitlines()
-    )
+    return set(Popen(["git", "tag"], stdout=PIPE).communicate()[0].splitlines())
 
 
 def git_is_clean():
-    return Popen(['git', 'diff', '--quiet']).wait() == 0
+    return Popen(["git", "diff", "--quiet"]).wait() == 0
 
 
 def make_git_commit(message, *args):
     message = message % args
-    Popen(['git', 'commit', '-am', message]).wait()
+    Popen(["git", "commit", "-am", message]).wait()
 
 
 def make_git_tag(tag):
     info('Tagging "%s"', tag)
-    Popen(['git', 'tag', tag]).wait()
+    Popen(["git", "tag", tag]).wait()
 
 
 def main():
-    os.chdir(os.path.join(os.path.dirname(__file__), '..'))
+    os.chdir(os.path.join(os.path.dirname(__file__), ".."))
 
     rv = parse_changelog()
 
     if rv is None:
-        fail('Could not parse changelog')
+        fail("Could not parse changelog")
 
     version, release_date, codename = rv
-    dev_version = bump_version(version) + '.dev'
+    dev_version = bump_version(version) + ".dev"
 
     info(
-        'Releasing %s (codename %s, release date %s)',
-        version, codename, release_date.strftime('%d/%m/%Y')
+        "Releasing %s (codename %s, release date %s)",
+        version,
+        codename,
+        release_date.strftime("%d/%m/%Y"),
     )
     tags = get_git_tags()
 
@@ -156,27 +155,24 @@ def main():
         fail('Version "%s" is already tagged', version)
 
     if release_date.date() != date.today():
-        fail(
-            'Release date is not today (%s != %s)',
-            release_date.date(), date.today()
-        )
+        fail("Release date is not today (%s != %s)", release_date.date(), date.today())
 
     if not git_is_clean():
-        fail('You have uncommitted changes in git')
+        fail("You have uncommitted changes in git")
 
     try:
         import wheel
     except ImportError:
-        fail('You need to install the wheel package.')
+        fail("You need to install the wheel package.")
 
     set_init_version(version)
     set_setup_version(version)
-    make_git_commit('Bump version number to %s', version)
+    make_git_commit("Bump version number to %s", version)
     make_git_tag(version)
     build_and_upload()
     set_init_version(dev_version)
     set_setup_version(dev_version)
 
 
-if __name__ == '__main__':
+if __name__ == "__main__":
     main()
index 55d8e35ca30e1e11f5cd541b63a9dfc25ae5bcea..02aed34d3acf38107e3fff7e20573655bc388bfa 100644 (file)
@@ -13,7 +13,7 @@
 import sys
 
 PY2 = sys.version_info[0] == 2
-PYPY = hasattr(sys, 'pypy_translation_info')
+PYPY = hasattr(sys, "pypy_translation_info")
 _identity = lambda x: x
 
 if not PY2:
@@ -29,6 +29,7 @@ if not PY2:
 
     import pickle
     from io import BytesIO, StringIO
+
     NativeStringIO = StringIO
 
     def reraise(tp, value, tb=None):
@@ -58,11 +59,13 @@ else:
 
     import cPickle as pickle
     from cStringIO import StringIO as BytesIO, StringIO
+
     NativeStringIO = BytesIO
 
-    exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
+    exec("def reraise(tp, value, tb=None):\n raise tp, value, tb")
 
     from itertools import imap, izip, ifilter
+
     intern = intern
 
     def implements_iterator(cls):
@@ -72,12 +75,12 @@ else:
 
     def implements_to_string(cls):
         cls.__unicode__ = cls.__str__
-        cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
+        cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
         return cls
 
     def encode_filename(filename):
         if isinstance(filename, unicode):
-            return filename.encode('utf-8')
+            return filename.encode("utf-8")
         return filename
 
 
@@ -89,7 +92,8 @@ def with_metaclass(meta, *bases):
     class metaclass(type):
         def __new__(cls, name, this_bases, d):
             return meta(name, bases, d)
-    return type.__new__(metaclass, 'temporary_class', (), {})
+
+    return type.__new__(metaclass, "temporary_class", (), {})
 
 
 try:
index 2eac35d5c35531b2b63e3fbdcae4bfd02dd89240..0a93e95680b01d7d40ba8ea231fa194038380299 100644 (file)
@@ -1,2 +1,2 @@
 # generated by scripts/generate_identifier_pattern.py
-pattern = '·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯'
+pattern = "·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯"
index 967dcb49144ae5055fa45cb327b291204dbd7877..451d3f8b8432e76a342dfdab5a1e4e4ff48d1513 100644 (file)
@@ -7,7 +7,7 @@ from .asyncsupport import auto_await
 
 async def auto_to_seq(value):
     seq = []
-    if hasattr(value, '__aiter__'):
+    if hasattr(value, "__aiter__"):
         async for item in value:
             seq.append(item)
     else:
@@ -17,8 +17,7 @@ async def auto_to_seq(value):
 
 
 async def async_select_or_reject(args, kwargs, modfunc, lookup_attr):
-    seq, func = filters.prepare_select_or_reject(
-        args, kwargs, modfunc, lookup_attr)
+    seq, func = filters.prepare_select_or_reject(args, kwargs, modfunc, lookup_attr)
     if seq:
         async for item in auto_aiter(seq):
             if func(item):
@@ -27,12 +26,13 @@ async def async_select_or_reject(args, kwargs, modfunc, lookup_attr):
 
 def dualfilter(normal_filter, async_filter):
     wrap_evalctx = False
-    if getattr(normal_filter, 'environmentfilter', False):
+    if getattr(normal_filter, "environmentfilter", False):
         is_async = lambda args: args[0].is_async
         wrap_evalctx = False
     else:
-        if not getattr(normal_filter, 'evalcontextfilter', False) and \
-           not getattr(normal_filter, 'contextfilter', False):
+        if not getattr(normal_filter, "evalcontextfilter", False) and not getattr(
+            normal_filter, "contextfilter", False
+        ):
             wrap_evalctx = True
         is_async = lambda args: args[0].environment.is_async
 
@@ -56,6 +56,7 @@ def dualfilter(normal_filter, async_filter):
 def asyncfiltervariant(original):
     def decorator(f):
         return dualfilter(original, f)
+
     return decorator
 
 
@@ -64,19 +65,22 @@ async def do_first(environment, seq):
     try:
         return await auto_aiter(seq).__anext__()
     except StopAsyncIteration:
-        return environment.undefined('No first item, sequence was empty.')
+        return environment.undefined("No first item, sequence was empty.")
 
 
 @asyncfiltervariant(filters.do_groupby)
 async def do_groupby(environment, value, attribute):
     expr = filters.make_attrgetter(environment, attribute)
-    return [filters._GroupTuple(key, await auto_to_seq(values))
-            for key, values in filters.groupby(sorted(
-                await auto_to_seq(value), key=expr), expr)]
+    return [
+        filters._GroupTuple(key, await auto_to_seq(values))
+        for key, values in filters.groupby(
+            sorted(await auto_to_seq(value), key=expr), expr
+        )
+    ]
 
 
 @asyncfiltervariant(filters.do_join)
-async def do_join(eval_ctx, value, d=u'', attribute=None):
+async def do_join(eval_ctx, value, d=u"", attribute=None):
     return filters.do_join(eval_ctx, await auto_to_seq(value), d, attribute)
 
 
@@ -131,17 +135,17 @@ async def do_slice(value, slices, fill_with=None):
 
 
 ASYNC_FILTERS = {
-    'first':        do_first,
-    'groupby':      do_groupby,
-    'join':         do_join,
-    'list':         do_list,
+    "first": do_first,
+    "groupby": do_groupby,
+    "join": do_join,
+    "list": do_list,
     # we intentionally do not support do_last because that would be
     # ridiculous
-    'reject':       do_reject,
-    'rejectattr':   do_rejectattr,
-    'map':          do_map,
-    'select':       do_select,
-    'selectattr':   do_selectattr,
-    'sum':          do_sum,
-    'slice':        do_slice,
+    "reject": do_reject,
+    "rejectattr": do_rejectattr,
+    "map": do_map,
+    "select": do_select,
+    "selectattr": do_selectattr,
+    "sum": do_sum,
+    "slice": do_slice,
 }
index f7da273b3087d787063d06dfd8fcd53c15a1514d..b2fd6e47a4097cdcf5dfc1063d5d3259212a5a45 100644 (file)
@@ -23,9 +23,11 @@ from .utils import missing
 
 async def concat_async(async_gen):
     rv = []
+
     async def collect():
         async for event in async_gen:
             rv.append(event)
+
     await collect()
     return concat(rv)
 
@@ -47,17 +49,18 @@ def wrap_generate_func(original_generate):
                 yield loop.run_until_complete(async_gen.__anext__())
         except StopAsyncIteration:
             pass
+
     def generate(self, *args, **kwargs):
         if not self.environment.is_async:
             return original_generate(self, *args, **kwargs)
         return _convert_generator(self, asyncio.get_event_loop(), args, kwargs)
+
     return update_wrapper(generate, original_generate)
 
 
 async def render_async(self, *args, **kwargs):
     if not self.environment.is_async:
-        raise RuntimeError('The environment was not created with async mode '
-                           'enabled.')
+        raise RuntimeError("The environment was not created with async mode enabled.")
 
     vars = dict(*args, **kwargs)
     ctx = self.new_context(vars)
@@ -74,6 +77,7 @@ def wrap_render_func(original_render):
             return original_render(self, *args, **kwargs)
         loop = asyncio.get_event_loop()
         return loop.run_until_complete(self.render_async(*args, **kwargs))
+
     return update_wrapper(render, original_render)
 
 
@@ -107,6 +111,7 @@ def wrap_macro_invoke(original_invoke):
         if not self._environment.is_async:
             return original_invoke(self, arguments, autoescape)
         return async_invoke(self, arguments, autoescape)
+
     return update_wrapper(_invoke, original_invoke)
 
 
@@ -122,9 +127,9 @@ def wrap_default_module(original_default_module):
     @internalcode
     def _get_default_module(self):
         if self.environment.is_async:
-            raise RuntimeError('Template module attribute is unavailable '
-                               'in async mode')
+            raise RuntimeError("Template module attribute is unavailable in async mode")
         return original_default_module(self)
+
     return _get_default_module
 
 
@@ -138,29 +143,29 @@ async def make_module_async(self, vars=None, shared=False, locals=None):
 
 def patch_template():
     from jinja2 import Template
+
     Template.generate = wrap_generate_func(Template.generate)
-    Template.generate_async = update_wrapper(
-        generate_async, Template.generate_async)
-    Template.render_async = update_wrapper(
-        render_async, Template.render_async)
+    Template.generate_async = update_wrapper(generate_async, Template.generate_async)
+    Template.render_async = update_wrapper(render_async, Template.render_async)
     Template.render = wrap_render_func(Template.render)
-    Template._get_default_module = wrap_default_module(
-        Template._get_default_module)
+    Template._get_default_module = wrap_default_module(Template._get_default_module)
     Template._get_default_module_async = get_default_module_async
     Template.make_module_async = update_wrapper(
-        make_module_async, Template.make_module_async)
+        make_module_async, Template.make_module_async
+    )
 
 
 def patch_runtime():
     from jinja2.runtime import BlockReference, Macro
-    BlockReference.__call__ = wrap_block_reference_call(
-        BlockReference.__call__)
+
+    BlockReference.__call__ = wrap_block_reference_call(BlockReference.__call__)
     Macro._invoke = wrap_macro_invoke(Macro._invoke)
 
 
 def patch_filters():
     from jinja2.filters import FILTERS
     from jinja2.asyncfilters import ASYNC_FILTERS
+
     FILTERS.update(ASYNC_FILTERS)
 
 
@@ -177,7 +182,7 @@ async def auto_await(value):
 
 
 async def auto_aiter(iterable):
-    if hasattr(iterable, '__aiter__'):
+    if hasattr(iterable, "__aiter__"):
         async for item in iterable:
             yield item
         return
@@ -252,6 +257,7 @@ class AsyncLoopContext(LoopContext):
 
 async def make_async_loop_context(iterable, undefined, recurse=None, depth0=0):
     import warnings
+
     warnings.warn(
         "This template must be recompiled with at least Jinja 2.11, or"
         " it will fail in 3.0.",
index 6466df6e986d2fd7d1cf29d5c7b0c3f49eb9db26..c2b877e635cb3550ba8c8ed927c552f28b361eb7 100644 (file)
@@ -56,9 +56,11 @@ bc_version = 3
 # reason for this is that Python tends to segfault if fed earlier bytecode
 # versions because someone thought it would be a good idea to reuse opcodes
 # or make Python incompatible with earlier versions.
-bc_magic = 'j2'.encode('ascii') + \
-    pickle.dumps(bc_version, 2) + \
-    pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1])
+bc_magic = (
+    "j2".encode("ascii")
+    + pickle.dumps(bc_version, 2)
+    + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1])
+)
 
 
 class Bucket(object):
@@ -102,7 +104,7 @@ class Bucket(object):
     def write_bytecode(self, f):
         """Dump the bytecode into the file or file like object passed."""
         if self.code is None:
-            raise TypeError('can\'t write empty bucket')
+            raise TypeError("can't write empty bucket")
         f.write(bc_magic)
         pickle.dump(self.checksum, f, 2)
         marshal_dump(self.code, f)
@@ -169,17 +171,17 @@ class BytecodeCache(object):
 
     def get_cache_key(self, name, filename=None):
         """Returns the unique hash key for this template name."""
-        hash = sha1(name.encode('utf-8'))
+        hash = sha1(name.encode("utf-8"))
         if filename is not None:
-            filename = '|' + filename
+            filename = "|" + filename
             if isinstance(filename, text_type):
-                filename = filename.encode('utf-8')
+                filename = filename.encode("utf-8")
             hash.update(filename)
         return hash.hexdigest()
 
     def get_source_checksum(self, source):
         """Returns a checksum for the source."""
-        return sha1(source.encode('utf-8')).hexdigest()
+        return sha1(source.encode("utf-8")).hexdigest()
 
     def get_bucket(self, environment, name, filename, source):
         """Return a cache bucket for the given template.  All arguments are
@@ -214,7 +216,7 @@ class FileSystemBytecodeCache(BytecodeCache):
     This bytecode cache supports clearing of the cache using the clear method.
     """
 
-    def __init__(self, directory=None, pattern='__jinja2_%s.cache'):
+    def __init__(self, directory=None, pattern="__jinja2_%s.cache"):
         if directory is None:
             directory = self._get_default_cache_dir()
         self.directory = directory
@@ -222,19 +224,21 @@ class FileSystemBytecodeCache(BytecodeCache):
 
     def _get_default_cache_dir(self):
         def _unsafe_dir():
-            raise RuntimeError('Cannot determine safe temp directory.  You '
-                               'need to explicitly provide one.')
+            raise RuntimeError(
+                "Cannot determine safe temp directory.  You "
+                "need to explicitly provide one."
+            )
 
         tmpdir = tempfile.gettempdir()
 
         # On windows the temporary directory is used specific unless
         # explicitly forced otherwise.  We can just use that.
-        if os.name == 'nt':
+        if os.name == "nt":
             return tmpdir
-        if not hasattr(os, 'getuid'):
+        if not hasattr(os, "getuid"):
             _unsafe_dir()
 
-        dirname = '_jinja2-cache-%d' % os.getuid()
+        dirname = "_jinja2-cache-%d" % os.getuid()
         actual_dir = os.path.join(tmpdir, dirname)
 
         try:
@@ -245,18 +249,22 @@ class FileSystemBytecodeCache(BytecodeCache):
         try:
             os.chmod(actual_dir, stat.S_IRWXU)
             actual_dir_stat = os.lstat(actual_dir)
-            if actual_dir_stat.st_uid != os.getuid() \
-               or not stat.S_ISDIR(actual_dir_stat.st_mode) \
-               or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU:
+            if (
+                actual_dir_stat.st_uid != os.getuid()
+                or not stat.S_ISDIR(actual_dir_stat.st_mode)
+                or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU
+            ):
                 _unsafe_dir()
         except OSError as e:
             if e.errno != errno.EEXIST:
                 raise
 
         actual_dir_stat = os.lstat(actual_dir)
-        if actual_dir_stat.st_uid != os.getuid() \
-           or not stat.S_ISDIR(actual_dir_stat.st_mode) \
-           or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU:
+        if (
+            actual_dir_stat.st_uid != os.getuid()
+            or not stat.S_ISDIR(actual_dir_stat.st_mode)
+            or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU
+        ):
             _unsafe_dir()
 
         return actual_dir
@@ -265,7 +273,7 @@ class FileSystemBytecodeCache(BytecodeCache):
         return path.join(self.directory, self.pattern % bucket.key)
 
     def load_bytecode(self, bucket):
-        f = open_if_exists(self._get_cache_filename(bucket), 'rb')
+        f = open_if_exists(self._get_cache_filename(bucket), "rb")
         if f is not None:
             try:
                 bucket.load_bytecode(f)
@@ -273,7 +281,7 @@ class FileSystemBytecodeCache(BytecodeCache):
                 f.close()
 
     def dump_bytecode(self, bucket):
-        f = open(self._get_cache_filename(bucket), 'wb')
+        f = open(self._get_cache_filename(bucket), "wb")
         try:
             bucket.write_bytecode(f)
         finally:
@@ -284,7 +292,8 @@ class FileSystemBytecodeCache(BytecodeCache):
         # write access on the file system and the function does not exist
         # normally.
         from os import remove
-        files = fnmatch.filter(listdir(self.directory), self.pattern % '*')
+
+        files = fnmatch.filter(listdir(self.directory), self.pattern % "*")
         for filename in files:
             try:
                 remove(path.join(self.directory, filename))
@@ -337,8 +346,13 @@ class MemcachedBytecodeCache(BytecodeCache):
        `ignore_memcache_errors` parameter.
     """
 
-    def __init__(self, client, prefix='jinja2/bytecode/', timeout=None,
-                 ignore_memcache_errors=True):
+    def __init__(
+        self,
+        client,
+        prefix="jinja2/bytecode/",
+        timeout=None,
+        ignore_memcache_errors=True,
+    ):
         self.client = client
         self.prefix = prefix
         self.timeout = timeout
index 308042ac5b53951c42c63ecc32dcd95cee5cd009..324bc0ffe5ba34678f99d3d3e8aff736647370da 100644 (file)
@@ -35,35 +35,35 @@ from .utils import Markup
 from .visitor import NodeVisitor
 
 operators = {
-    'eq':       '==',
-    'ne':       '!=',
-    'gt':       '>',
-    'gteq':     '>=',
-    'lt':       '<',
-    'lteq':     '<=',
-    'in':       'in',
-    'notin':    'not in'
+    "eq": "==",
+    "ne": "!=",
+    "gt": ">",
+    "gteq": ">=",
+    "lt": "<",
+    "lteq": "<=",
+    "in": "in",
+    "notin": "not in",
 }
 
 # what method to iterate over items do we want to use for dict iteration
 # in generated code?  on 2.x let's go with iteritems, on 3.x with items
-if hasattr(dict, 'iteritems'):
-    dict_item_iter = 'iteritems'
+if hasattr(dict, "iteritems"):
+    dict_item_iter = "iteritems"
 else:
-    dict_item_iter = 'items'
+    dict_item_iter = "items"
 
-code_features = ['division']
+code_features = ["division"]
 
 # does this python version support generator stops? (PEP 0479)
 try:
-    exec('from __future__ import generator_stop')
-    code_features.append('generator_stop')
+    exec("from __future__ import generator_stop")
+    code_features.append("generator_stop")
 except SyntaxError:
     pass
 
 # does this python version support yield from?
 try:
-    exec('def f(): yield from x()')
+    exec("def f(): yield from x()")
 except SyntaxError:
     supports_yield_from = False
 else:
@@ -78,17 +78,19 @@ def optimizeconst(f):
             if new_node != node:
                 return self.visit(new_node, frame)
         return f(self, node, frame, **kwargs)
+
     return update_wrapper(new_func, f)
 
 
-def generate(node, environment, name, filename, stream=None,
-             defer_init=False, optimized=True):
+def generate(
+    node, environment, name, filename, stream=None, defer_init=False, optimized=True
+):
     """Generate the python source for a node tree."""
     if not isinstance(node, nodes.Template):
-        raise TypeError('Can\'t compile non template nodes')
-    generator = environment.code_generator_class(environment, name, filename,
-                                                 stream, defer_init,
-                                                 optimized)
+        raise TypeError("Can't compile non template nodes")
+    generator = environment.code_generator_class(
+        environment, name, filename, stream, defer_init, optimized
+    )
     generator.visit(node)
     if stream is None:
         return generator.stream.getvalue()
@@ -129,7 +131,6 @@ def find_undeclared(nodes, names):
 
 
 class MacroRef(object):
-
     def __init__(self, node):
         self.node = node
         self.accesses_caller = False
@@ -142,8 +143,7 @@ class Frame(object):
 
     def __init__(self, eval_ctx, parent=None, level=None):
         self.eval_ctx = eval_ctx
-        self.symbols = Symbols(parent and parent.symbols or None,
-                               level=level)
+        self.symbols = Symbols(parent and parent.symbols or None, level=level)
 
         # a toplevel frame is the root + soft frames such as if conditions.
         self.toplevel = False
@@ -233,7 +233,7 @@ class UndeclaredNameVisitor(NodeVisitor):
         self.undeclared = set()
 
     def visit_Name(self, node):
-        if node.ctx == 'load' and node.name in self.names:
+        if node.ctx == "load" and node.name in self.names:
             self.undeclared.add(node.name)
             if self.undeclared == self.names:
                 raise VisitorExit()
@@ -252,9 +252,9 @@ class CompilerExit(Exception):
 
 
 class CodeGenerator(NodeVisitor):
-
-    def __init__(self, environment, name, filename, stream=None,
-                 defer_init=False, optimized=True):
+    def __init__(
+        self, environment, name, filename, stream=None, defer_init=False, optimized=True
+    ):
         if stream is None:
             stream = NativeStringIO()
         self.environment = environment
@@ -316,7 +316,7 @@ class CodeGenerator(NodeVisitor):
         self._param_def_block = []
 
         # Tracks the current context.
-        self._context_reference_stack = ['context']
+        self._context_reference_stack = ["context"]
 
     # -- Various compilation helpers
 
@@ -327,30 +327,30 @@ class CodeGenerator(NodeVisitor):
     def temporary_identifier(self):
         """Get a new unique identifier."""
         self._last_identifier += 1
-        return 't_%d' % self._last_identifier
+        return "t_%d" % self._last_identifier
 
     def buffer(self, frame):
         """Enable buffering for the frame from that point onwards."""
         frame.buffer = self.temporary_identifier()
-        self.writeline('%s = []' % frame.buffer)
+        self.writeline("%s = []" % frame.buffer)
 
     def return_buffer_contents(self, frame, force_unescaped=False):
         """Return the buffer contents of the frame."""
         if not force_unescaped:
             if frame.eval_ctx.volatile:
-                self.writeline('if context.eval_ctx.autoescape:')
+                self.writeline("if context.eval_ctx.autoescape:")
                 self.indent()
-                self.writeline('return Markup(concat(%s))' % frame.buffer)
+                self.writeline("return Markup(concat(%s))" % frame.buffer)
                 self.outdent()
-                self.writeline('else:')
+                self.writeline("else:")
                 self.indent()
-                self.writeline('return concat(%s)' % frame.buffer)
+                self.writeline("return concat(%s)" % frame.buffer)
                 self.outdent()
                 return
             elif frame.eval_ctx.autoescape:
-                self.writeline('return Markup(concat(%s))' % frame.buffer)
+                self.writeline("return Markup(concat(%s))" % frame.buffer)
                 return
-        self.writeline('return concat(%s)' % frame.buffer)
+        self.writeline("return concat(%s)" % frame.buffer)
 
     def indent(self):
         """Indent by one."""
@@ -363,14 +363,14 @@ class CodeGenerator(NodeVisitor):
     def start_write(self, frame, node=None):
         """Yield or write into the frame buffer."""
         if frame.buffer is None:
-            self.writeline('yield ', node)
+            self.writeline("yield ", node)
         else:
-            self.writeline('%s.append(' % frame.buffer, node)
+            self.writeline("%s.append(" % frame.buffer, node)
 
     def end_write(self, frame):
         """End the writing process started by `start_write`."""
         if frame.buffer is not None:
-            self.write(')')
+            self.write(")")
 
     def simple_write(self, s, frame, node=None):
         """Simple shortcut for start_write + write + end_write."""
@@ -383,7 +383,7 @@ class CodeGenerator(NodeVisitor):
         is no buffer a dummy ``if 0: yield None`` is written automatically.
         """
         try:
-            self.writeline('pass')
+            self.writeline("pass")
             for node in nodes:
                 self.visit(node, frame)
         except CompilerExit:
@@ -393,14 +393,13 @@ class CodeGenerator(NodeVisitor):
         """Write a string into the output stream."""
         if self._new_lines:
             if not self._first_write:
-                self.stream.write('\n' * self._new_lines)
+                self.stream.write("\n" * self._new_lines)
                 self.code_lineno += self._new_lines
                 if self._write_debug_info is not None:
-                    self.debug_info.append((self._write_debug_info,
-                                            self.code_lineno))
+                    self.debug_info.append((self._write_debug_info, self.code_lineno))
                     self._write_debug_info = None
             self._first_write = False
-            self.stream.write('    ' * self._indentation)
+            self.stream.write("    " * self._indentation)
             self._new_lines = 0
         self.stream.write(x)
 
@@ -432,41 +431,41 @@ class CodeGenerator(NodeVisitor):
                 break
 
         for arg in node.args:
-            self.write(', ')
+            self.write(", ")
             self.visit(arg, frame)
 
         if not kwarg_workaround:
             for kwarg in node.kwargs:
-                self.write(', ')
+                self.write(", ")
                 self.visit(kwarg, frame)
             if extra_kwargs is not None:
                 for key, value in iteritems(extra_kwargs):
-                    self.write(', %s=%s' % (key, value))
+                    self.write(", %s=%s" % (key, value))
         if node.dyn_args:
-            self.write(', *')
+            self.write(", *")
             self.visit(node.dyn_args, frame)
 
         if kwarg_workaround:
             if node.dyn_kwargs is not None:
-                self.write(', **dict({')
+                self.write(", **dict({")
             else:
-                self.write(', **{')
+                self.write(", **{")
             for kwarg in node.kwargs:
-                self.write('%r: ' % kwarg.key)
+                self.write("%r: " % kwarg.key)
                 self.visit(kwarg.value, frame)
-                self.write(', ')
+                self.write(", ")
             if extra_kwargs is not None:
                 for key, value in iteritems(extra_kwargs):
-                    self.write('%r: %s, ' % (key, value))
+                    self.write("%r: %s, " % (key, value))
             if node.dyn_kwargs is not None:
-                self.write('}, **')
+                self.write("}, **")
                 self.visit(node.dyn_kwargs, frame)
-                self.write(')')
+                self.write(")")
             else:
-                self.write('}')
+                self.write("}")
 
         elif node.dyn_kwargs is not None:
-            self.write(', **')
+            self.write(", **")
             self.visit(node.dyn_kwargs, frame)
 
     def pull_dependencies(self, nodes):
@@ -474,13 +473,14 @@ class CodeGenerator(NodeVisitor):
         visitor = DependencyFinderVisitor()
         for node in nodes:
             visitor.visit(node)
-        for dependency in 'filters', 'tests':
+        for dependency in "filters", "tests":
             mapping = getattr(self, dependency)
             for name in getattr(visitor, dependency):
                 if name not in mapping:
                     mapping[name] = self.temporary_identifier()
-                self.writeline('%s = environment.%s[%r]' %
-                               (mapping[name], dependency, name))
+                self.writeline(
+                    "%s = environment.%s[%r]" % (mapping[name], dependency, name)
+                )
 
     def enter_frame(self, frame):
         undefs = []
@@ -488,16 +488,15 @@ class CodeGenerator(NodeVisitor):
             if action == VAR_LOAD_PARAMETER:
                 pass
             elif action == VAR_LOAD_RESOLVE:
-                self.writeline('%s = %s(%r)' %
-                               (target, self.get_resolve_func(), param))
+                self.writeline("%s = %s(%r)" % (target, self.get_resolve_func(), param))
             elif action == VAR_LOAD_ALIAS:
-                self.writeline('%s = %s' % (target, param))
+                self.writeline("%s = %s" % (target, param))
             elif action == VAR_LOAD_UNDEFINED:
                 undefs.append(target)
             else:
-                raise NotImplementedError('unknown load instruction')
+                raise NotImplementedError("unknown load instruction")
         if undefs:
-            self.writeline('%s = missing' % ' = '.join(undefs))
+            self.writeline("%s = missing" % " = ".join(undefs))
 
     def leave_frame(self, frame, with_python_scope=False):
         if not with_python_scope:
@@ -505,12 +504,12 @@ class CodeGenerator(NodeVisitor):
             for target, _ in iteritems(frame.symbols.loads):
                 undefs.append(target)
             if undefs:
-                self.writeline('%s = missing' % ' = '.join(undefs))
+                self.writeline("%s = missing" % " = ".join(undefs))
 
     def func(self, name):
         if self.environment.is_async:
-            return 'async def %s' % name
-        return 'def %s' % name
+            return "async def %s" % name
+        return "def %s" % name
 
     def macro_body(self, node, frame):
         """Dump the function def of a macro or call block."""
@@ -522,15 +521,15 @@ class CodeGenerator(NodeVisitor):
         skip_special_params = set()
         args = []
         for idx, arg in enumerate(node.args):
-            if arg.name == 'caller':
+            if arg.name == "caller":
                 explicit_caller = idx
-            if arg.name in ('kwargs', 'varargs'):
+            if arg.name in ("kwargs", "varargs"):
                 skip_special_params.add(arg.name)
             args.append(frame.symbols.ref(arg.name))
 
-        undeclared = find_undeclared(node.body, ('caller', 'kwargs', 'varargs'))
+        undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs"))
 
-        if 'caller' in undeclared:
+        if "caller" in undeclared:
             # In older Jinja versions there was a bug that allowed caller
             # to retain the special behavior even if it was mentioned in
             # the argument list.  However thankfully this was only really
@@ -541,23 +540,26 @@ class CodeGenerator(NodeVisitor):
                 try:
                     node.defaults[explicit_caller - len(node.args)]
                 except IndexError:
-                    self.fail('When defining macros or call blocks the '
-                              'special "caller" argument must be omitted '
-                              'or be given a default.', node.lineno)
+                    self.fail(
+                        "When defining macros or call blocks the "
+                        'special "caller" argument must be omitted '
+                        "or be given a default.",
+                        node.lineno,
+                    )
             else:
-                args.append(frame.symbols.declare_parameter('caller'))
+                args.append(frame.symbols.declare_parameter("caller"))
             macro_ref.accesses_caller = True
-        if 'kwargs' in undeclared and not 'kwargs' in skip_special_params:
-            args.append(frame.symbols.declare_parameter('kwargs'))
+        if "kwargs" in undeclared and not "kwargs" in skip_special_params:
+            args.append(frame.symbols.declare_parameter("kwargs"))
             macro_ref.accesses_kwargs = True
-        if 'varargs' in undeclared and not 'varargs' in skip_special_params:
-            args.append(frame.symbols.declare_parameter('varargs'))
+        if "varargs" in undeclared and not "varargs" in skip_special_params:
+            args.append(frame.symbols.declare_parameter("varargs"))
             macro_ref.accesses_varargs = True
 
         # macros are delayed, they never require output checks
         frame.require_output_check = False
         frame.symbols.analyze_node(node)
-        self.writeline('%s(%s):' % (self.func('macro'), ', '.join(args)), node)
+        self.writeline("%s(%s):" % (self.func("macro"), ", ".join(args)), node)
         self.indent()
 
         self.buffer(frame)
@@ -566,17 +568,17 @@ class CodeGenerator(NodeVisitor):
         self.push_parameter_definitions(frame)
         for idx, arg in enumerate(node.args):
             ref = frame.symbols.ref(arg.name)
-            self.writeline('if %s is missing:' % ref)
+            self.writeline("if %s is missing:" % ref)
             self.indent()
             try:
                 default = node.defaults[idx - len(node.args)]
             except IndexError:
-                self.writeline('%s = undefined(%r, name=%r)' % (
-                    ref,
-                    'parameter %r was not provided' % arg.name,
-                    arg.name))
+                self.writeline(
+                    "%s = undefined(%r, name=%r)"
+                    % (ref, "parameter %r was not provided" % arg.name, arg.name)
+                )
             else:
-                self.writeline('%s = ' % ref)
+                self.writeline("%s = " % ref)
                 self.visit(default, frame)
             self.mark_parameter_stored(ref)
             self.outdent()
@@ -591,38 +593,46 @@ class CodeGenerator(NodeVisitor):
 
     def macro_def(self, macro_ref, frame):
         """Dump the macro definition for the def created by macro_body."""
-        arg_tuple = ', '.join(repr(x.name) for x in macro_ref.node.args)
-        name = getattr(macro_ref.node, 'name', None)
+        arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args)
+        name = getattr(macro_ref.node, "name", None)
         if len(macro_ref.node.args) == 1:
-            arg_tuple += ','
-        self.write('Macro(environment, macro, %r, (%s), %r, %r, %r, '
-                   'context.eval_ctx.autoescape)' %
-                   (name, arg_tuple, macro_ref.accesses_kwargs,
-                    macro_ref.accesses_varargs, macro_ref.accesses_caller))
+            arg_tuple += ","
+        self.write(
+            "Macro(environment, macro, %r, (%s), %r, %r, %r, "
+            "context.eval_ctx.autoescape)"
+            % (
+                name,
+                arg_tuple,
+                macro_ref.accesses_kwargs,
+                macro_ref.accesses_varargs,
+                macro_ref.accesses_caller,
+            )
+        )
 
     def position(self, node):
         """Return a human readable position for the node."""
-        rv = 'line %d' % node.lineno
+        rv = "line %d" % node.lineno
         if self.name is not None:
-            rv += ' in ' + repr(self.name)
+            rv += " in " + repr(self.name)
         return rv
 
     def dump_local_context(self, frame):
-        return '{%s}' % ', '.join(
-            '%r: %s' % (name, target) for name, target
-            in iteritems(frame.symbols.dump_stores()))
+        return "{%s}" % ", ".join(
+            "%r: %s" % (name, target)
+            for name, target in iteritems(frame.symbols.dump_stores())
+        )
 
     def write_commons(self):
         """Writes a common preamble that is used by root and block functions.
         Primarily this sets up common local helpers and enforces a generator
         through a dead branch.
         """
-        self.writeline('resolve = context.resolve_or_missing')
-        self.writeline('undefined = environment.undefined')
+        self.writeline("resolve = context.resolve_or_missing")
+        self.writeline("undefined = environment.undefined")
         # always use the standard Undefined class for the implicit else of
         # conditional expressions
-        self.writeline('cond_expr_undefined = Undefined')
-        self.writeline('if 0: yield None')
+        self.writeline("cond_expr_undefined = Undefined")
+        self.writeline("if 0: yield None")
 
     def push_parameter_definitions(self, frame):
         """Pushes all parameter targets from the given frame into a local
@@ -655,12 +665,12 @@ class CodeGenerator(NodeVisitor):
 
     def get_resolve_func(self):
         target = self._context_reference_stack[-1]
-        if target == 'context':
-            return 'resolve'
-        return '%s.resolve' % target
+        if target == "context":
+            return "resolve"
+        return "%s.resolve" % target
 
     def derive_context(self, frame):
-        return '%s.derived(%s)' % (
+        return "%s.derived(%s)" % (
             self.get_context_ref(),
             self.dump_local_context(frame),
         )
@@ -682,44 +692,48 @@ class CodeGenerator(NodeVisitor):
         vars = self._assign_stack.pop()
         if not frame.toplevel or not vars:
             return
-        public_names = [x for x in vars if x[:1] != '_']
+        public_names = [x for x in vars if x[:1] != "_"]
         if len(vars) == 1:
             name = next(iter(vars))
             ref = frame.symbols.ref(name)
-            self.writeline('context.vars[%r] = %s' % (name, ref))
+            self.writeline("context.vars[%r] = %s" % (name, ref))
         else:
-            self.writeline('context.vars.update({')
+            self.writeline("context.vars.update({")
             for idx, name in enumerate(vars):
                 if idx:
-                    self.write(', ')
+                    self.write(", ")
                 ref = frame.symbols.ref(name)
-                self.write('%r: %s' % (name, ref))
-            self.write('})')
+                self.write("%r: %s" % (name, ref))
+            self.write("})")
         if public_names:
             if len(public_names) == 1:
-                self.writeline('context.exported_vars.add(%r)' %
-                               public_names[0])
+                self.writeline("context.exported_vars.add(%r)" % public_names[0])
             else:
-                self.writeline('context.exported_vars.update((%s))' %
-                               ', '.join(imap(repr, public_names)))
+                self.writeline(
+                    "context.exported_vars.update((%s))"
+                    % ", ".join(imap(repr, public_names))
+                )
 
     # -- Statement Visitors
 
     def visit_Template(self, node, frame=None):
-        assert frame is None, 'no root frame allowed'
+        assert frame is None, "no root frame allowed"
         eval_ctx = EvalContext(self.environment, self.name)
 
         from jinja2.runtime import __all__ as exported
-        self.writeline('from __future__ import %s' % ', '.join(code_features))
-        self.writeline('from jinja2.runtime import ' + ', '.join(exported))
+
+        self.writeline("from __future__ import %s" % ", ".join(code_features))
+        self.writeline("from jinja2.runtime import " + ", ".join(exported))
 
         if self.environment.is_async:
-            self.writeline('from jinja2.asyncsupport import auto_await, '
-                           'auto_aiter, AsyncLoopContext')
+            self.writeline(
+                "from jinja2.asyncsupport import auto_await, "
+                "auto_aiter, AsyncLoopContext"
+            )
 
         # if we want a deferred initialization we cannot move the
         # environment into a local name
-        envenv = not self.defer_init and ', environment=environment' or ''
+        envenv = not self.defer_init and ", environment=environment" or ""
 
         # do we have an extends tag at all?  If not, we can save some
         # overhead by just not processing any inheritance code.
@@ -728,7 +742,7 @@ class CodeGenerator(NodeVisitor):
         # find all blocks
         for block in node.find_all(nodes.Block):
             if block.name in self.blocks:
-                self.fail('block %r defined twice' % block.name, block.lineno)
+                self.fail("block %r defined twice" % block.name, block.lineno)
             self.blocks[block.name] = block
 
         # find all imports and import them
@@ -736,32 +750,32 @@ class CodeGenerator(NodeVisitor):
             if import_.importname not in self.import_aliases:
                 imp = import_.importname
                 self.import_aliases[imp] = alias = self.temporary_identifier()
-                if '.' in imp:
-                    module, obj = imp.rsplit('.', 1)
-                    self.writeline('from %s import %s as %s' %
-                                   (module, obj, alias))
+                if "." in imp:
+                    module, obj = imp.rsplit(".", 1)
+                    self.writeline("from %s import %s as %s" % (module, obj, alias))
                 else:
-                    self.writeline('import %s as %s' % (imp, alias))
+                    self.writeline("import %s as %s" % (imp, alias))
 
         # add the load name
-        self.writeline('name = %r' % self.name)
+        self.writeline("name = %r" % self.name)
 
         # generate the root render function.
-        self.writeline('%s(context, missing=missing%s):' %
-                       (self.func('root'), envenv), extra=1)
+        self.writeline(
+            "%s(context, missing=missing%s):" % (self.func("root"), envenv), extra=1
+        )
         self.indent()
         self.write_commons()
 
         # process the root
         frame = Frame(eval_ctx)
-        if 'self' in find_undeclared(node.body, ('self',)):
-            ref = frame.symbols.declare_parameter('self')
-            self.writeline('%s = TemplateReference(context)' % ref)
+        if "self" in find_undeclared(node.body, ("self",)):
+            ref = frame.symbols.declare_parameter("self")
+            self.writeline("%s = TemplateReference(context)" % ref)
         frame.symbols.analyze_node(node)
         frame.toplevel = frame.rootlevel = True
         frame.require_output_check = have_extends and not self.has_known_extends
         if have_extends:
-            self.writeline('parent_template = None')
+            self.writeline("parent_template = None")
         self.enter_frame(frame)
         self.pull_dependencies(node.body)
         self.blockvisit(node.body, frame)
@@ -772,39 +786,42 @@ class CodeGenerator(NodeVisitor):
         if have_extends:
             if not self.has_known_extends:
                 self.indent()
-                self.writeline('if parent_template is not None:')
+                self.writeline("if parent_template is not None:")
             self.indent()
             if supports_yield_from and not self.environment.is_async:
-                self.writeline('yield from parent_template.'
-                               'root_render_func(context)')
+                self.writeline("yield from parent_template.root_render_func(context)")
             else:
-                self.writeline('%sfor event in parent_template.'
-                               'root_render_func(context):' %
-                               (self.environment.is_async and 'async ' or ''))
+                self.writeline(
+                    "%sfor event in parent_template."
+                    "root_render_func(context):"
+                    % (self.environment.is_async and "async " or "")
+                )
                 self.indent()
-                self.writeline('yield event')
+                self.writeline("yield event")
                 self.outdent()
             self.outdent(1 + (not self.has_known_extends))
 
         # at this point we now have the blocks collected and can visit them too.
         for name, block in iteritems(self.blocks):
-            self.writeline('%s(context, missing=missing%s):' %
-                           (self.func('block_' + name), envenv),
-                           block, 1)
+            self.writeline(
+                "%s(context, missing=missing%s):"
+                % (self.func("block_" + name), envenv),
+                block,
+                1,
+            )
             self.indent()
             self.write_commons()
             # It's important that we do not make this frame a child of the
             # toplevel template.  This would cause a variety of
             # interesting issues with identifier tracking.
             block_frame = Frame(eval_ctx)
-            undeclared = find_undeclared(block.body, ('self', 'super'))
-            if 'self' in undeclared:
-                ref = block_frame.symbols.declare_parameter('self')
-                self.writeline('%s = TemplateReference(context)' % ref)
-            if 'super' in undeclared:
-                ref = block_frame.symbols.declare_parameter('super')
-                self.writeline('%s = context.super(%r, '
-                               'block_%s)' % (ref, name, name))
+            undeclared = find_undeclared(block.body, ("self", "super"))
+            if "self" in undeclared:
+                ref = block_frame.symbols.declare_parameter("self")
+                self.writeline("%s = TemplateReference(context)" % ref)
+            if "super" in undeclared:
+                ref = block_frame.symbols.declare_parameter("super")
+                self.writeline("%s = context.super(%r, block_%s)" % (ref, name, name))
             block_frame.symbols.analyze_node(block)
             block_frame.block = name
             self.enter_frame(block_frame)
@@ -813,13 +830,15 @@ class CodeGenerator(NodeVisitor):
             self.leave_frame(block_frame, with_python_scope=True)
             self.outdent()
 
-        self.writeline('blocks = {%s}' % ', '.join('%r: block_%s' % (x, x)
-                                                   for x in self.blocks),
-                       extra=1)
+        self.writeline(
+            "blocks = {%s}" % ", ".join("%r: block_%s" % (x, x) for x in self.blocks),
+            extra=1,
+        )
 
         # add a function that returns the debug info
-        self.writeline('debug_info = %r' % '&'.join('%s=%s' % x for x
-                                                    in self.debug_info))
+        self.writeline(
+            "debug_info = %r" % "&".join("%s=%s" % x for x in self.debug_info)
+        )
 
     def visit_Block(self, node, frame):
         """Call a block and register it for the template."""
@@ -830,7 +849,7 @@ class CodeGenerator(NodeVisitor):
             if self.has_known_extends:
                 return
             if self.extends_so_far > 0:
-                self.writeline('if parent_template is None:')
+                self.writeline("if parent_template is None:")
                 self.indent()
                 level += 1
 
@@ -839,16 +858,22 @@ class CodeGenerator(NodeVisitor):
         else:
             context = self.get_context_ref()
 
-        if supports_yield_from and not self.environment.is_async and \
-           frame.buffer is None:
-            self.writeline('yield from context.blocks[%r][0](%s)' % (
-                           node.name, context), node)
+        if (
+            supports_yield_from
+            and not self.environment.is_async
+            and frame.buffer is None
+        ):
+            self.writeline(
+                "yield from context.blocks[%r][0](%s)" % (node.name, context), node
+            )
         else:
-            loop = self.environment.is_async and 'async for' or 'for'
-            self.writeline('%s event in context.blocks[%r][0](%s):' % (
-                           loop, node.name, context), node)
+            loop = self.environment.is_async and "async for" or "for"
+            self.writeline(
+                "%s event in context.blocks[%r][0](%s):" % (loop, node.name, context),
+                node,
+            )
             self.indent()
-            self.simple_write('event', frame)
+            self.simple_write("event", frame)
             self.outdent()
 
         self.outdent(level)
@@ -856,8 +881,7 @@ class CodeGenerator(NodeVisitor):
     def visit_Extends(self, node, frame):
         """Calls the extender."""
         if not frame.toplevel:
-            self.fail('cannot use extend from a non top-level scope',
-                      node.lineno)
+            self.fail("cannot use extend from a non top-level scope", node.lineno)
 
         # if the number of extends statements in general is zero so
         # far, we don't have to add a check if something extended
@@ -869,10 +893,9 @@ class CodeGenerator(NodeVisitor):
             # time too, but i welcome it not to confuse users by throwing the
             # same error at different times just "because we can".
             if not self.has_known_extends:
-                self.writeline('if parent_template is not None:')
+                self.writeline("if parent_template is not None:")
                 self.indent()
-            self.writeline('raise TemplateRuntimeError(%r)' %
-                           'extended multiple times')
+            self.writeline("raise TemplateRuntimeError(%r)" % "extended multiple times")
 
             # if we have a known extends already we don't need that code here
             # as we know that the template execution will end here.
@@ -881,14 +904,14 @@ class CodeGenerator(NodeVisitor):
             else:
                 self.outdent()
 
-        self.writeline('parent_template = environment.get_template(', node)
+        self.writeline("parent_template = environment.get_template(", node)
         self.visit(node.template, frame)
-        self.write(', %r)' % self.name)
-        self.writeline('for name, parent_block in parent_template.'
-                       'blocks.%s():' % dict_item_iter)
+        self.write(", %r)" % self.name)
+        self.writeline(
+            "for name, parent_block in parent_template.blocks.%s():" % dict_item_iter
+        )
         self.indent()
-        self.writeline('context.blocks.setdefault(name, []).'
-                       'append(parent_block)')
+        self.writeline("context.blocks.setdefault(name, []).append(parent_block)")
         self.outdent()
 
         # if this extends statement was in the root level we can take
@@ -903,52 +926,56 @@ class CodeGenerator(NodeVisitor):
     def visit_Include(self, node, frame):
         """Handles includes."""
         if node.ignore_missing:
-            self.writeline('try:')
+            self.writeline("try:")
             self.indent()
 
-        func_name = 'get_or_select_template'
+        func_name = "get_or_select_template"
         if isinstance(node.template, nodes.Const):
             if isinstance(node.template.value, string_types):
-                func_name = 'get_template'
+                func_name = "get_template"
             elif isinstance(node.template.value, (tuple, list)):
-                func_name = 'select_template'
+                func_name = "select_template"
         elif isinstance(node.template, (nodes.Tuple, nodes.List)):
-            func_name = 'select_template'
+            func_name = "select_template"
 
-        self.writeline('template = environment.%s(' % func_name, node)
+        self.writeline("template = environment.%s(" % func_name, node)
         self.visit(node.template, frame)
-        self.write(', %r)' % self.name)
+        self.write(", %r)" % self.name)
         if node.ignore_missing:
             self.outdent()
-            self.writeline('except TemplateNotFound:')
+            self.writeline("except TemplateNotFound:")
             self.indent()
-            self.writeline('pass')
+            self.writeline("pass")
             self.outdent()
-            self.writeline('else:')
+            self.writeline("else:")
             self.indent()
 
         skip_event_yield = False
         if node.with_context:
-            loop = self.environment.is_async and 'async for' or 'for'
-            self.writeline('%s event in template.root_render_func('
-                           'template.new_context(context.get_all(), True, '
-                           '%s)):' % (loop, self.dump_local_context(frame)))
+            loop = self.environment.is_async and "async for" or "for"
+            self.writeline(
+                "%s event in template.root_render_func("
+                "template.new_context(context.get_all(), True, "
+                "%s)):" % (loop, self.dump_local_context(frame))
+            )
         elif self.environment.is_async:
-            self.writeline('for event in (await '
-                           'template._get_default_module_async())'
-                           '._body_stream:')
+            self.writeline(
+                "for event in (await "
+                "template._get_default_module_async())"
+                "._body_stream:"
+            )
         else:
             if supports_yield_from:
-                self.writeline('yield from template._get_default_module()'
-                               '._body_stream')
+                self.writeline("yield from template._get_default_module()._body_stream")
                 skip_event_yield = True
             else:
-                self.writeline('for event in template._get_default_module()'
-                               '._body_stream:')
+                self.writeline(
+                    "for event in template._get_default_module()._body_stream:"
+                )
 
         if not skip_event_yield:
             self.indent()
-            self.simple_write('event', frame)
+            self.simple_write("event", frame)
             self.outdent()
 
         if node.ignore_missing:
@@ -956,40 +983,50 @@ class CodeGenerator(NodeVisitor):
 
     def visit_Import(self, node, frame):
         """Visit regular imports."""
-        self.writeline('%s = ' % frame.symbols.ref(node.target), node)
+        self.writeline("%s = " % frame.symbols.ref(node.target), node)
         if frame.toplevel:
-            self.write('context.vars[%r] = ' % node.target)
+            self.write("context.vars[%r] = " % node.target)
         if self.environment.is_async:
-            self.write('await ')
-        self.write('environment.get_template(')
+            self.write("await ")
+        self.write("environment.get_template(")
         self.visit(node.template, frame)
-        self.write(', %r).' % self.name)
+        self.write(", %r)." % self.name)
         if node.with_context:
-            self.write('make_module%s(context.get_all(), True, %s)'
-                       % (self.environment.is_async and '_async' or '',
-                          self.dump_local_context(frame)))
+            self.write(
+                "make_module%s(context.get_all(), True, %s)"
+                % (
+                    self.environment.is_async and "_async" or "",
+                    self.dump_local_context(frame),
+                )
+            )
         elif self.environment.is_async:
-            self.write('_get_default_module_async()')
+            self.write("_get_default_module_async()")
         else:
-            self.write('_get_default_module()')
-        if frame.toplevel and not node.target.startswith('_'):
-            self.writeline('context.exported_vars.discard(%r)' % node.target)
+            self.write("_get_default_module()")
+        if frame.toplevel and not node.target.startswith("_"):
+            self.writeline("context.exported_vars.discard(%r)" % node.target)
 
     def visit_FromImport(self, node, frame):
         """Visit named imports."""
         self.newline(node)
-        self.write('included_template = %senvironment.get_template('
-                   % (self.environment.is_async and 'await ' or ''))
+        self.write(
+            "included_template = %senvironment.get_template("
+            % (self.environment.is_async and "await " or "")
+        )
         self.visit(node.template, frame)
-        self.write(', %r).' % self.name)
+        self.write(", %r)." % self.name)
         if node.with_context:
-            self.write('make_module%s(context.get_all(), True, %s)'
-                       % (self.environment.is_async and '_async' or '',
-                          self.dump_local_context(frame)))
+            self.write(
+                "make_module%s(context.get_all(), True, %s)"
+                % (
+                    self.environment.is_async and "_async" or "",
+                    self.dump_local_context(frame),
+                )
+            )
         elif self.environment.is_async:
-            self.write('_get_default_module_async()')
+            self.write("_get_default_module_async()")
         else:
-            self.write('_get_default_module()')
+            self.write("_get_default_module()")
 
         var_names = []
         discarded_names = []
@@ -998,41 +1035,51 @@ class CodeGenerator(NodeVisitor):
                 name, alias = name
             else:
                 alias = name
-            self.writeline('%s = getattr(included_template, '
-                           '%r, missing)' % (frame.symbols.ref(alias), name))
-            self.writeline('if %s is missing:' % frame.symbols.ref(alias))
+            self.writeline(
+                "%s = getattr(included_template, "
+                "%r, missing)" % (frame.symbols.ref(alias), name)
+            )
+            self.writeline("if %s is missing:" % frame.symbols.ref(alias))
             self.indent()
-            self.writeline('%s = undefined(%r %% '
-                           'included_template.__name__, '
-                           'name=%r)' %
-                           (frame.symbols.ref(alias),
-                            'the template %%r (imported on %s) does '
-                            'not export the requested name %s' % (
-                                self.position(node),
-                                repr(name)
-                           ), name))
+            self.writeline(
+                "%s = undefined(%r %% "
+                "included_template.__name__, "
+                "name=%r)"
+                % (
+                    frame.symbols.ref(alias),
+                    "the template %%r (imported on %s) does "
+                    "not export the requested name %s"
+                    % (self.position(node), repr(name)),
+                    name,
+                )
+            )
             self.outdent()
             if frame.toplevel:
                 var_names.append(alias)
-                if not alias.startswith('_'):
+                if not alias.startswith("_"):
                     discarded_names.append(alias)
 
         if var_names:
             if len(var_names) == 1:
                 name = var_names[0]
-                self.writeline('context.vars[%r] = %s' %
-                               (name, frame.symbols.ref(name)))
+                self.writeline(
+                    "context.vars[%r] = %s" % (name, frame.symbols.ref(name))
+                )
             else:
-                self.writeline('context.vars.update({%s})' % ', '.join(
-                    '%r: %s' % (name, frame.symbols.ref(name)) for name in var_names
-                ))
+                self.writeline(
+                    "context.vars.update({%s})"
+                    % ", ".join(
+                        "%r: %s" % (name, frame.symbols.ref(name)) for name in var_names
+                    )
+                )
         if discarded_names:
             if len(discarded_names) == 1:
-                self.writeline('context.exported_vars.discard(%r)' %
-                               discarded_names[0])
+                self.writeline("context.exported_vars.discard(%r)" % discarded_names[0])
             else:
-                self.writeline('context.exported_vars.difference_'
-                               'update((%s))' % ', '.join(imap(repr, discarded_names)))
+                self.writeline(
+                    "context.exported_vars.difference_"
+                    "update((%s))" % ", ".join(imap(repr, discarded_names))
+                )
 
     def visit_For(self, node, frame):
         loop_frame = frame.inner()
@@ -1042,35 +1089,35 @@ class CodeGenerator(NodeVisitor):
         # try to figure out if we have an extended loop.  An extended loop
         # is necessary if the loop is in recursive mode if the special loop
         # variable is accessed in the body.
-        extended_loop = node.recursive or 'loop' in \
-                        find_undeclared(node.iter_child_nodes(
-                            only=('body',)), ('loop',))
+        extended_loop = node.recursive or "loop" in find_undeclared(
+            node.iter_child_nodes(only=("body",)), ("loop",)
+        )
 
         loop_ref = None
         if extended_loop:
-            loop_ref = loop_frame.symbols.declare_parameter('loop')
+            loop_ref = loop_frame.symbols.declare_parameter("loop")
 
-        loop_frame.symbols.analyze_node(node, for_branch='body')
+        loop_frame.symbols.analyze_node(node, for_branch="body")
         if node.else_:
-            else_frame.symbols.analyze_node(node, for_branch='else')
+            else_frame.symbols.analyze_node(node, for_branch="else")
 
         if node.test:
             loop_filter_func = self.temporary_identifier()
-            test_frame.symbols.analyze_node(node, for_branch='test')
-            self.writeline('%s(fiter):' % self.func(loop_filter_func), node.test)
+            test_frame.symbols.analyze_node(node, for_branch="test")
+            self.writeline("%s(fiter):" % self.func(loop_filter_func), node.test)
             self.indent()
             self.enter_frame(test_frame)
-            self.writeline(self.environment.is_async and 'async for ' or 'for ')
+            self.writeline(self.environment.is_async and "async for " or "for ")
             self.visit(node.target, loop_frame)
-            self.write(' in ')
-            self.write(self.environment.is_async and 'auto_aiter(fiter)' or 'fiter')
-            self.write(':')
+            self.write(" in ")
+            self.write(self.environment.is_async and "auto_aiter(fiter)" or "fiter")
+            self.write(":")
             self.indent()
-            self.writeline('if ', node.test)
+            self.writeline("if ", node.test)
             self.visit(node.test, test_frame)
-            self.write(':')
+            self.write(":")
             self.indent()
-            self.writeline('yield ')
+            self.writeline("yield ")
             self.visit(node.target, loop_frame)
             self.outdent(3)
             self.leave_frame(test_frame, with_python_scope=True)
@@ -1079,8 +1126,9 @@ class CodeGenerator(NodeVisitor):
         # variables at that point.  Because loops can be nested but the loop
         # variable is a special one we have to enforce aliasing for it.
         if node.recursive:
-            self.writeline('%s(reciter, loop_render_func, depth=0):' %
-                           self.func('loop'), node)
+            self.writeline(
+                "%s(reciter, loop_render_func, depth=0):" % self.func("loop"), node
+            )
             self.indent()
             self.buffer(loop_frame)
 
@@ -1090,57 +1138,60 @@ class CodeGenerator(NodeVisitor):
         # make sure the loop variable is a special one and raise a template
         # assertion error if a loop tries to write to loop
         if extended_loop:
-            self.writeline('%s = missing' % loop_ref)
+            self.writeline("%s = missing" % loop_ref)
 
         for name in node.find_all(nodes.Name):
-            if name.ctx == 'store' and name.name == 'loop':
-                self.fail('Can\'t assign to special loop variable '
-                          'in for-loop target', name.lineno)
+            if name.ctx == "store" and name.name == "loop":
+                self.fail(
+                    "Can't assign to special loop variable in for-loop target",
+                    name.lineno,
+                )
 
         if node.else_:
             iteration_indicator = self.temporary_identifier()
-            self.writeline('%s = 1' % iteration_indicator)
+            self.writeline("%s = 1" % iteration_indicator)
 
-        self.writeline(self.environment.is_async and 'async for ' or 'for ', node)
+        self.writeline(self.environment.is_async and "async for " or "for ", node)
         self.visit(node.target, loop_frame)
         if extended_loop:
             if self.environment.is_async:
-                self.write(', %s in AsyncLoopContext(' % loop_ref)
+                self.write(", %s in AsyncLoopContext(" % loop_ref)
             else:
-                self.write(', %s in LoopContext(' % loop_ref)
+                self.write(", %s in LoopContext(" % loop_ref)
         else:
-            self.write(' in ')
+            self.write(" in ")
 
         if node.test:
-            self.write('%s(' % loop_filter_func)
+            self.write("%s(" % loop_filter_func)
         if node.recursive:
-            self.write('reciter')
+            self.write("reciter")
         else:
             if self.environment.is_async and not extended_loop:
-                self.write('auto_aiter(')
+                self.write("auto_aiter(")
             self.visit(node.iter, frame)
             if self.environment.is_async and not extended_loop:
-                self.write(')')
+                self.write(")")
         if node.test:
-            self.write(')')
+            self.write(")")
 
         if node.recursive:
-            self.write(', undefined, loop_render_func, depth):')
+            self.write(", undefined, loop_render_func, depth):")
         else:
-            self.write(extended_loop and ', undefined):' or ':')
+            self.write(extended_loop and ", undefined):" or ":")
 
         self.indent()
         self.enter_frame(loop_frame)
 
         self.blockvisit(node.body, loop_frame)
         if node.else_:
-            self.writeline('%s = 0' % iteration_indicator)
+            self.writeline("%s = 0" % iteration_indicator)
         self.outdent()
-        self.leave_frame(loop_frame, with_python_scope=node.recursive
-                         and not node.else_)
+        self.leave_frame(
+            loop_frame, with_python_scope=node.recursive and not node.else_
+        )
 
         if node.else_:
-            self.writeline('if %s:' % iteration_indicator)
+            self.writeline("if %s:" % iteration_indicator)
             self.indent()
             self.enter_frame(else_frame)
             self.blockvisit(node.else_, else_frame)
@@ -1154,33 +1205,33 @@ class CodeGenerator(NodeVisitor):
             self.outdent()
             self.start_write(frame, node)
             if self.environment.is_async:
-                self.write('await ')
-            self.write('loop(')
+                self.write("await ")
+            self.write("loop(")
             if self.environment.is_async:
-                self.write('auto_aiter(')
+                self.write("auto_aiter(")
             self.visit(node.iter, frame)
             if self.environment.is_async:
-                self.write(')')
-            self.write(', loop)')
+                self.write(")")
+            self.write(", loop)")
             self.end_write(frame)
 
     def visit_If(self, node, frame):
         if_frame = frame.soft()
-        self.writeline('if ', node)
+        self.writeline("if ", node)
         self.visit(node.test, if_frame)
-        self.write(':')
+        self.write(":")
         self.indent()
         self.blockvisit(node.body, if_frame)
         self.outdent()
         for elif_ in node.elif_:
-            self.writeline('elif ', elif_)
+            self.writeline("elif ", elif_)
             self.visit(elif_.test, if_frame)
-            self.write(':')
+            self.write(":")
             self.indent()
             self.blockvisit(elif_.body, if_frame)
             self.outdent()
         if node.else_:
-            self.writeline('else:')
+            self.writeline("else:")
             self.indent()
             self.blockvisit(node.else_, if_frame)
             self.outdent()
@@ -1189,16 +1240,16 @@ class CodeGenerator(NodeVisitor):
         macro_frame, macro_ref = self.macro_body(node, frame)
         self.newline()
         if frame.toplevel:
-            if not node.name.startswith('_'):
-                self.write('context.exported_vars.add(%r)' % node.name)
+            if not node.name.startswith("_"):
+                self.write("context.exported_vars.add(%r)" % node.name)
             ref = frame.symbols.ref(node.name)
-            self.writeline('context.vars[%r] = ' % node.name)
-        self.write('%s = ' % frame.symbols.ref(node.name))
+            self.writeline("context.vars[%r] = " % node.name)
+        self.write("%s = " % frame.symbols.ref(node.name))
         self.macro_def(macro_ref, macro_frame)
 
     def visit_CallBlock(self, node, frame):
         call_frame, macro_ref = self.macro_body(node, frame)
-        self.writeline('caller = ')
+        self.writeline("caller = ")
         self.macro_def(macro_ref, call_frame)
         self.start_write(frame, node)
         self.visit_Call(node.call, frame, forward_caller=True)
@@ -1222,7 +1273,7 @@ class CodeGenerator(NodeVisitor):
         for idx, (target, expr) in enumerate(izip(node.targets, node.values)):
             self.newline()
             self.visit(target, with_frame)
-            self.write(' = ')
+            self.write(" = ")
             self.visit(expr, frame)
         self.blockvisit(node.body, with_frame)
         self.leave_frame(with_frame)
@@ -1411,7 +1462,7 @@ class CodeGenerator(NodeVisitor):
         self.push_assign_tracking()
         self.newline(node)
         self.visit(node.target, frame)
-        self.write(' = ')
+        self.write(" = ")
         self.visit(node.node, frame)
         self.pop_assign_tracking(frame)
 
@@ -1428,20 +1479,19 @@ class CodeGenerator(NodeVisitor):
         self.blockvisit(node.body, block_frame)
         self.newline(node)
         self.visit(node.target, frame)
-        self.write(' = (Markup if context.eval_ctx.autoescape '
-                   'else identity)(')
+        self.write(" = (Markup if context.eval_ctx.autoescape else identity)(")
         if node.filter is not None:
             self.visit_Filter(node.filter, block_frame)
         else:
-            self.write('concat(%s)' % block_frame.buffer)
-        self.write(')')
+            self.write("concat(%s)" % block_frame.buffer)
+        self.write(")")
         self.pop_assign_tracking(frame)
         self.leave_frame(block_frame)
 
     # -- Expression Visitors
 
     def visit_Name(self, node, frame):
-        if node.ctx == 'store' and frame.toplevel:
+        if node.ctx == "store" and frame.toplevel:
             if self._assign_stack:
                 self._assign_stack[-1].add(node.name)
         ref = frame.symbols.ref(node.name)
@@ -1449,12 +1499,17 @@ class CodeGenerator(NodeVisitor):
         # If we are looking up a variable we might have to deal with the
         # case where it's undefined.  We can skip that case if the load
         # instruction indicates a parameter which are always defined.
-        if node.ctx == 'load':
+        if node.ctx == "load":
             load = frame.symbols.find_load(ref)
-            if not (load is not None and load[0] == VAR_LOAD_PARAMETER and \
-                    not self.parameter_is_undeclared(ref)):
-                self.write('(undefined(name=%r) if %s is missing else %s)' %
-                           (node.name, ref, ref))
+            if not (
+                load is not None
+                and load[0] == VAR_LOAD_PARAMETER
+                and not self.parameter_is_undeclared(ref)
+            ):
+                self.write(
+                    "(undefined(name=%r) if %s is missing else %s)"
+                    % (node.name, ref, ref)
+                )
                 return
 
         self.write(ref)
@@ -1464,12 +1519,14 @@ class CodeGenerator(NodeVisitor):
         # `foo.bar` notation they will be parsed as a normal attribute access
         # when used anywhere but in a `set` context
         ref = frame.symbols.ref(node.name)
-        self.writeline('if not isinstance(%s, Namespace):' % ref)
+        self.writeline("if not isinstance(%s, Namespace):" % ref)
         self.indent()
-        self.writeline('raise TemplateRuntimeError(%r)' %
-                       'cannot assign attribute on non-namespace object')
+        self.writeline(
+            "raise TemplateRuntimeError(%r)"
+            % "cannot assign attribute on non-namespace object"
+        )
         self.outdent()
-        self.writeline('%s[%r]' % (ref, node.attr))
+        self.writeline("%s[%r]" % (ref, node.attr))
 
     def visit_Const(self, node, frame):
         val = node.as_const(frame.eval_ctx)
@@ -1482,105 +1539,111 @@ class CodeGenerator(NodeVisitor):
         try:
             self.write(repr(node.as_const(frame.eval_ctx)))
         except nodes.Impossible:
-            self.write('(Markup if context.eval_ctx.autoescape else identity)(%r)'
-                       % node.data)
+            self.write(
+                "(Markup if context.eval_ctx.autoescape else identity)(%r)" % node.data
+            )
 
     def visit_Tuple(self, node, frame):
-        self.write('(')
+        self.write("(")
         idx = -1
         for idx, item in enumerate(node.items):
             if idx:
-                self.write(', ')
+                self.write(", ")
             self.visit(item, frame)
-        self.write(idx == 0 and ',)' or ')')
+        self.write(idx == 0 and ",)" or ")")
 
     def visit_List(self, node, frame):
-        self.write('[')
+        self.write("[")
         for idx, item in enumerate(node.items):
             if idx:
-                self.write(', ')
+                self.write(", ")
             self.visit(item, frame)
-        self.write(']')
+        self.write("]")
 
     def visit_Dict(self, node, frame):
-        self.write('{')
+        self.write("{")
         for idx, item in enumerate(node.items):
             if idx:
-                self.write(', ')
+                self.write(", ")
             self.visit(item.key, frame)
-            self.write(': ')
+            self.write(": ")
             self.visit(item.value, frame)
-        self.write('}')
+        self.write("}")
 
     def binop(operator, interceptable=True):
         @optimizeconst
         def visitor(self, node, frame):
-            if self.environment.sandboxed and \
-               operator in self.environment.intercepted_binops:
-                self.write('environment.call_binop(context, %r, ' % operator)
+            if (
+                self.environment.sandboxed
+                and operator in self.environment.intercepted_binops
+            ):
+                self.write("environment.call_binop(context, %r, " % operator)
                 self.visit(node.left, frame)
-                self.write(', ')
+                self.write(", ")
                 self.visit(node.right, frame)
             else:
-                self.write('(')
+                self.write("(")
                 self.visit(node.left, frame)
-                self.write(' %s ' % operator)
+                self.write(" %s " % operator)
                 self.visit(node.right, frame)
-            self.write(')')
+            self.write(")")
+
         return visitor
 
     def uaop(operator, interceptable=True):
         @optimizeconst
         def visitor(self, node, frame):
-            if self.environment.sandboxed and \
-               operator in self.environment.intercepted_unops:
-                self.write('environment.call_unop(context, %r, ' % operator)
+            if (
+                self.environment.sandboxed
+                and operator in self.environment.intercepted_unops
+            ):
+                self.write("environment.call_unop(context, %r, " % operator)
                 self.visit(node.node, frame)
             else:
-                self.write('(' + operator)
+                self.write("(" + operator)
                 self.visit(node.node, frame)
-            self.write(')')
+            self.write(")")
+
         return visitor
 
-    visit_Add = binop('+')
-    visit_Sub = binop('-')
-    visit_Mul = binop('*')
-    visit_Div = binop('/')
-    visit_FloorDiv = binop('//')
-    visit_Pow = binop('**')
-    visit_Mod = binop('%')
-    visit_And = binop('and', interceptable=False)
-    visit_Or = binop('or', interceptable=False)
-    visit_Pos = uaop('+')
-    visit_Neg = uaop('-')
-    visit_Not = uaop('not ', interceptable=False)
+    visit_Add = binop("+")
+    visit_Sub = binop("-")
+    visit_Mul = binop("*")
+    visit_Div = binop("/")
+    visit_FloorDiv = binop("//")
+    visit_Pow = binop("**")
+    visit_Mod = binop("%")
+    visit_And = binop("and", interceptable=False)
+    visit_Or = binop("or", interceptable=False)
+    visit_Pos = uaop("+")
+    visit_Neg = uaop("-")
+    visit_Not = uaop("not ", interceptable=False)
     del binop, uaop
 
     @optimizeconst
     def visit_Concat(self, node, frame):
         if frame.eval_ctx.volatile:
-            func_name = '(context.eval_ctx.volatile and' \
-                        ' markup_join or unicode_join)'
+            func_name = "(context.eval_ctx.volatile and markup_join or unicode_join)"
         elif frame.eval_ctx.autoescape:
-            func_name = 'markup_join'
+            func_name = "markup_join"
         else:
-            func_name = 'unicode_join'
-        self.write('%s((' % func_name)
+            func_name = "unicode_join"
+        self.write("%s((" % func_name)
         for arg in node.nodes:
             self.visit(arg, frame)
-            self.write(', ')
-        self.write('))')
+            self.write(", ")
+        self.write("))")
 
     @optimizeconst
     def visit_Compare(self, node, frame):
-        self.write('(')
+        self.write("(")
         self.visit(node.expr, frame)
         for op in node.ops:
             self.visit(op, frame)
-        self.write(')')
+        self.write(")")
 
     def visit_Operand(self, node, frame):
-        self.write(' %s ' % operators[node.op])
+        self.write(" %s " % operators[node.op])
         self.visit(node.expr, frame)
 
     @optimizeconst
@@ -1588,9 +1651,9 @@ class CodeGenerator(NodeVisitor):
         if self.environment.is_async:
             self.write("await auto_await(")
 
-        self.write('environment.getattr(')
+        self.write("environment.getattr(")
         self.visit(node.node, frame)
-        self.write(', %r)' % node.attr)
+        self.write(", %r)" % node.attr)
 
         if self.environment.is_async:
             self.write(")")
@@ -1600,18 +1663,18 @@ class CodeGenerator(NodeVisitor):
         # slices bypass the environment getitem method.
         if isinstance(node.arg, nodes.Slice):
             self.visit(node.node, frame)
-            self.write('[')
+            self.write("[")
             self.visit(node.arg, frame)
-            self.write(']')
+            self.write("]")
         else:
             if self.environment.is_async:
                 self.write("await auto_await(")
 
-            self.write('environment.getitem(')
+            self.write("environment.getitem(")
             self.visit(node.node, frame)
-            self.write(', ')
+            self.write(", ")
             self.visit(node.arg, frame)
-            self.write(')')
+            self.write(")")
 
             if self.environment.is_async:
                 self.write(")")
@@ -1619,107 +1682,113 @@ class CodeGenerator(NodeVisitor):
     def visit_Slice(self, node, frame):
         if node.start is not None:
             self.visit(node.start, frame)
-        self.write(':')
+        self.write(":")
         if node.stop is not None:
             self.visit(node.stop, frame)
         if node.step is not None:
-            self.write(':')
+            self.write(":")
             self.visit(node.step, frame)
 
     @optimizeconst
     def visit_Filter(self, node, frame):
         if self.environment.is_async:
-            self.write('await auto_await(')
-        self.write(self.filters[node.name] + '(')
+            self.write("await auto_await(")
+        self.write(self.filters[node.name] + "(")
         func = self.environment.filters.get(node.name)
         if func is None:
-            self.fail('no filter named %r' % node.name, node.lineno)
-        if getattr(func, 'contextfilter', False):
-            self.write('context, ')
-        elif getattr(func, 'evalcontextfilter', False):
-            self.write('context.eval_ctx, ')
-        elif getattr(func, 'environmentfilter', False):
-            self.write('environment, ')
+            self.fail("no filter named %r" % node.name, node.lineno)
+        if getattr(func, "contextfilter", False):
+            self.write("context, ")
+        elif getattr(func, "evalcontextfilter", False):
+            self.write("context.eval_ctx, ")
+        elif getattr(func, "environmentfilter", False):
+            self.write("environment, ")
 
         # if the filter node is None we are inside a filter block
         # and want to write to the current buffer
         if node.node is not None:
             self.visit(node.node, frame)
         elif frame.eval_ctx.volatile:
-            self.write('(context.eval_ctx.autoescape and'
-                       ' Markup(concat(%s)) or concat(%s))' %
-                       (frame.buffer, frame.buffer))
+            self.write(
+                "(context.eval_ctx.autoescape and"
+                " Markup(concat(%s)) or concat(%s))" % (frame.buffer, frame.buffer)
+            )
         elif frame.eval_ctx.autoescape:
-            self.write('Markup(concat(%s))' % frame.buffer)
+            self.write("Markup(concat(%s))" % frame.buffer)
         else:
-            self.write('concat(%s)' % frame.buffer)
+            self.write("concat(%s)" % frame.buffer)
         self.signature(node, frame)
-        self.write(')')
+        self.write(")")
         if self.environment.is_async:
-            self.write(')')
+            self.write(")")
 
     @optimizeconst
     def visit_Test(self, node, frame):
-        self.write(self.tests[node.name] + '(')
+        self.write(self.tests[node.name] + "(")
         if node.name not in self.environment.tests:
-            self.fail('no test named %r' % node.name, node.lineno)
+            self.fail("no test named %r" % node.name, node.lineno)
         self.visit(node.node, frame)
         self.signature(node, frame)
-        self.write(')')
+        self.write(")")
 
     @optimizeconst
     def visit_CondExpr(self, node, frame):
         def write_expr2():
             if node.expr2 is not None:
                 return self.visit(node.expr2, frame)
-            self.write('cond_expr_undefined(%r)' % ('the inline if-'
-                       'expression on %s evaluated to false and '
-                       'no else section was defined.' % self.position(node)))
-
-        self.write('(')
+            self.write(
+                "cond_expr_undefined(%r)"
+                % (
+                    "the inline if-"
+                    "expression on %s evaluated to false and "
+                    "no else section was defined." % self.position(node)
+                )
+            )
+
+        self.write("(")
         self.visit(node.expr1, frame)
-        self.write(' if ')
+        self.write(" if ")
         self.visit(node.test, frame)
-        self.write(' else ')
+        self.write(" else ")
         write_expr2()
-        self.write(')')
+        self.write(")")
 
     @optimizeconst
     def visit_Call(self, node, frame, forward_caller=False):
         if self.environment.is_async:
-            self.write('await auto_await(')
+            self.write("await auto_await(")
         if self.environment.sandboxed:
-            self.write('environment.call(context, ')
+            self.write("environment.call(context, ")
         else:
-            self.write('context.call(')
+            self.write("context.call(")
         self.visit(node.node, frame)
-        extra_kwargs = forward_caller and {'caller': 'caller'} or None
+        extra_kwargs = forward_caller and {"caller": "caller"} or None
         self.signature(node, frame, extra_kwargs)
-        self.write(')')
+        self.write(")")
         if self.environment.is_async:
-            self.write(')')
+            self.write(")")
 
     def visit_Keyword(self, node, frame):
-        self.write(node.key + '=')
+        self.write(node.key + "=")
         self.visit(node.value, frame)
 
     # -- Unused nodes for extensions
 
     def visit_MarkSafe(self, node, frame):
-        self.write('Markup(')
+        self.write("Markup(")
         self.visit(node.expr, frame)
-        self.write(')')
+        self.write(")")
 
     def visit_MarkSafeIfAutoescape(self, node, frame):
-        self.write('(context.eval_ctx.autoescape and Markup or identity)(')
+        self.write("(context.eval_ctx.autoescape and Markup or identity)(")
         self.visit(node.expr, frame)
-        self.write(')')
+        self.write(")")
 
     def visit_EnvironmentAttribute(self, node, frame):
-        self.write('environment.' + node.name)
+        self.write("environment." + node.name)
 
     def visit_ExtensionAttribute(self, node, frame):
-        self.write('environment.extensions[%r].%s' % (node.identifier, node.name))
+        self.write("environment.extensions[%r].%s" % (node.identifier, node.name))
 
     def visit_ImportedName(self, node, frame):
         self.write(self.import_aliases[node.importname])
@@ -1728,16 +1797,16 @@ class CodeGenerator(NodeVisitor):
         self.write(node.name)
 
     def visit_ContextReference(self, node, frame):
-        self.write('context')
+        self.write("context")
 
     def visit_DerivedContextReference(self, node, frame):
         self.write(self.derive_context(frame))
 
     def visit_Continue(self, node, frame):
-        self.writeline('continue', node)
+        self.writeline("continue", node)
 
     def visit_Break(self, node, frame):
-        self.writeline('break', node)
+        self.writeline("break", node)
 
     def visit_Scope(self, node, frame):
         scope_frame = frame.inner()
@@ -1748,8 +1817,8 @@ class CodeGenerator(NodeVisitor):
 
     def visit_OverlayScope(self, node, frame):
         ctx = self.temporary_identifier()
-        self.writeline('%s = %s' % (ctx, self.derive_context(frame)))
-        self.writeline('%s.vars = ' % ctx)
+        self.writeline("%s = %s" % (ctx, self.derive_context(frame)))
+        self.writeline("%s.vars = " % ctx)
         self.visit(node.context, frame)
         self.push_context_reference(ctx)
 
@@ -1762,7 +1831,7 @@ class CodeGenerator(NodeVisitor):
 
     def visit_EvalContextModifier(self, node, frame):
         for keyword in node.options:
-            self.writeline('context.eval_ctx.%s = ' % keyword.key)
+            self.writeline("context.eval_ctx.%s = " % keyword.key)
             self.visit(keyword.value, frame)
             try:
                 val = keyword.value.as_const(frame.eval_ctx)
@@ -1774,9 +1843,9 @@ class CodeGenerator(NodeVisitor):
     def visit_ScopedEvalContextModifier(self, node, frame):
         old_ctx_name = self.temporary_identifier()
         saved_ctx = frame.eval_ctx.save()
-        self.writeline('%s = context.eval_ctx.save()' % old_ctx_name)
+        self.writeline("%s = context.eval_ctx.save()" % old_ctx_name)
         self.visit_EvalContextModifier(node, frame)
         for child in node.body:
             self.visit(child, frame)
         frame.eval_ctx.revert(saved_ctx)
-        self.writeline('context.eval_ctx.revert(%s)' % old_ctx_name)
+        self.writeline("context.eval_ctx.revert(%s)" % old_ctx_name)
index 8d6a6a71aa9bd234bf01bb2087491c03a282979b..36da88bfe34ca763c3450dcd2bb4446dc9e823a8 100644 (file)
@@ -9,7 +9,7 @@
     :license: BSD, see LICENSE for more details.
 """
 #: list of lorem ipsum words used by the lipsum() helper function
-LOREM_IPSUM_WORDS = u'''\
+LOREM_IPSUM_WORDS = u"""\
 a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at
 auctor augue bibendum blandit class commodo condimentum congue consectetuer
 consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus
@@ -27,4 +27,4 @@ ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit
 sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor
 tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices
 ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus
-viverra volutpat vulputate'''
+viverra volutpat vulputate"""
index 23e891d421c770ba3ce2ad13ea6f384361268d43..bb366094739135040cef61fe901e802cdb454d91 100644 (file)
@@ -100,7 +100,7 @@ def fake_traceback(exc_value, tb, filename, lineno):
         "__jinja_exception__": exc_value,
     }
     # Raise an exception at the correct line number.
-    code = compile('\n' * (lineno - 1) + "raise __jinja_exception__", filename, "exec")
+    code = compile("\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec")
 
     # Build a new code object that points to the template file and
     # replaces the location with a block name.
@@ -213,6 +213,8 @@ if sys.version_info >= (3, 7):
     def tb_set_next(tb, tb_next):
         tb.tb_next = tb_next
         return tb
+
+
 elif PYPY:
     # PyPy might have special support, and won't work with ctypes.
     try:
@@ -221,6 +223,7 @@ elif PYPY:
         # Without tproxy support, use the original traceback.
         def tb_set_next(tb, tb_next):
             return tb
+
     else:
         # With tproxy support, create a proxy around the traceback that
         # returns the new tb_next.
@@ -232,6 +235,8 @@ elif PYPY:
                 return op.delegate()
 
             return tputil.make_proxy(controller, obj=tb)
+
+
 else:
     # Use ctypes to assign tb_next at the C level since it's read-only
     # from Python.
index 135ef81fefc643ea64c9c1e4d78fd943d25cdd75..8ee52bb227eb7314fcd4ffb0487287e74336a31d 100644 (file)
@@ -15,40 +15,41 @@ from .utils import Joiner
 from .utils import Namespace
 
 # defaults for the parser / lexer
-BLOCK_START_STRING = '{%'
-BLOCK_END_STRING = '%}'
-VARIABLE_START_STRING = '{{'
-VARIABLE_END_STRING = '}}'
-COMMENT_START_STRING = '{#'
-COMMENT_END_STRING = '#}'
+BLOCK_START_STRING = "{%"
+BLOCK_END_STRING = "%}"
+VARIABLE_START_STRING = "{{"
+VARIABLE_END_STRING = "}}"
+COMMENT_START_STRING = "{#"
+COMMENT_END_STRING = "#}"
 LINE_STATEMENT_PREFIX = None
 LINE_COMMENT_PREFIX = None
 TRIM_BLOCKS = False
 LSTRIP_BLOCKS = False
-NEWLINE_SEQUENCE = '\n'
+NEWLINE_SEQUENCE = "\n"
 KEEP_TRAILING_NEWLINE = False
 
 # default filters, tests and namespace
 from jinja2.filters import FILTERS as DEFAULT_FILTERS
 from jinja2.tests import TESTS as DEFAULT_TESTS
+
 DEFAULT_NAMESPACE = {
-    'range':        range_type,
-    'dict':         dict,
-    'lipsum':       generate_lorem_ipsum,
-    'cycler':       Cycler,
-    'joiner':       Joiner,
-    'namespace':    Namespace
+    "range": range_type,
+    "dict": dict,
+    "lipsum": generate_lorem_ipsum,
+    "cycler": Cycler,
+    "joiner": Joiner,
+    "namespace": Namespace,
 }
 
 # default policies
 DEFAULT_POLICIES = {
-    'compiler.ascii_str':   True,
-    'urlize.rel':           'noopener',
-    'urlize.target':        None,
-    'truncate.leeway':      5,
-    'json.dumps_function':  None,
-    'json.dumps_kwargs':    {'sort_keys': True},
-    'ext.i18n.trimmed':     False,
+    "compiler.ascii_str": True,
+    "urlize.rel": "noopener",
+    "urlize.target": None,
+    "truncate.leeway": 5,
+    "json.dumps_function": None,
+    "json.dumps_kwargs": {"sort_keys": True},
+    "ext.i18n.trimmed": False,
 }
 
 # export all constants
index 252d7eb26a1cd8b8578335066f775aa04b7e1be5..7c4d26a7b9b2fc6aab00c79b8c22a007a0e2ce76 100644 (file)
@@ -123,20 +123,25 @@ def fail_for_missing_callable(string, name):
         try:
             name._fail_with_undefined_error()
         except Exception as e:
-            msg = '%s (%s; did you forget to quote the callable name?)' % (msg, e)
+            msg = "%s (%s; did you forget to quote the callable name?)" % (msg, e)
     raise TemplateRuntimeError(msg)
 
 
 def _environment_sanity_check(environment):
     """Perform a sanity check on the environment."""
-    assert issubclass(environment.undefined, Undefined), 'undefined must ' \
-        'be a subclass of undefined because filters depend on it.'
-    assert environment.block_start_string != \
-        environment.variable_start_string != \
-        environment.comment_start_string, 'block, variable and comment ' \
-        'start strings must be different'
-    assert environment.newline_sequence in ('\r', '\r\n', '\n'), \
-        'newline_sequence set to unknown line ending string.'
+    assert issubclass(
+        environment.undefined, Undefined
+    ), "undefined must be a subclass of undefined because filters depend on it."
+    assert (
+        environment.block_start_string
+        != environment.variable_start_string
+        != environment.comment_start_string
+    ), "block, variable and comment start strings must be different"
+    assert environment.newline_sequence in (
+        "\r",
+        "\r\n",
+        "\n",
+    ), "newline_sequence set to unknown line ending string."
     return environment
 
 
@@ -287,29 +292,31 @@ class Environment(object):
     #: :class:`~jinja2.runtime.Context` for more information.
     context_class = Context
 
-    def __init__(self,
-                 block_start_string=BLOCK_START_STRING,
-                 block_end_string=BLOCK_END_STRING,
-                 variable_start_string=VARIABLE_START_STRING,
-                 variable_end_string=VARIABLE_END_STRING,
-                 comment_start_string=COMMENT_START_STRING,
-                 comment_end_string=COMMENT_END_STRING,
-                 line_statement_prefix=LINE_STATEMENT_PREFIX,
-                 line_comment_prefix=LINE_COMMENT_PREFIX,
-                 trim_blocks=TRIM_BLOCKS,
-                 lstrip_blocks=LSTRIP_BLOCKS,
-                 newline_sequence=NEWLINE_SEQUENCE,
-                 keep_trailing_newline=KEEP_TRAILING_NEWLINE,
-                 extensions=(),
-                 optimized=True,
-                 undefined=Undefined,
-                 finalize=None,
-                 autoescape=False,
-                 loader=None,
-                 cache_size=400,
-                 auto_reload=True,
-                 bytecode_cache=None,
-                 enable_async=False):
+    def __init__(
+        self,
+        block_start_string=BLOCK_START_STRING,
+        block_end_string=BLOCK_END_STRING,
+        variable_start_string=VARIABLE_START_STRING,
+        variable_end_string=VARIABLE_END_STRING,
+        comment_start_string=COMMENT_START_STRING,
+        comment_end_string=COMMENT_END_STRING,
+        line_statement_prefix=LINE_STATEMENT_PREFIX,
+        line_comment_prefix=LINE_COMMENT_PREFIX,
+        trim_blocks=TRIM_BLOCKS,
+        lstrip_blocks=LSTRIP_BLOCKS,
+        newline_sequence=NEWLINE_SEQUENCE,
+        keep_trailing_newline=KEEP_TRAILING_NEWLINE,
+        extensions=(),
+        optimized=True,
+        undefined=Undefined,
+        finalize=None,
+        autoescape=False,
+        loader=None,
+        cache_size=400,
+        auto_reload=True,
+        bytecode_cache=None,
+        enable_async=False,
+    ):
         # !!Important notice!!
         #   The constructor accepts quite a few arguments that should be
         #   passed by keyword rather than position.  However it's important to
@@ -381,15 +388,28 @@ class Environment(object):
             if not hasattr(self, key):
                 setattr(self, key, value)
 
-    def overlay(self, block_start_string=missing, block_end_string=missing,
-                variable_start_string=missing, variable_end_string=missing,
-                comment_start_string=missing, comment_end_string=missing,
-                line_statement_prefix=missing, line_comment_prefix=missing,
-                trim_blocks=missing, lstrip_blocks=missing,
-                extensions=missing, optimized=missing,
-                undefined=missing, finalize=missing, autoescape=missing,
-                loader=missing, cache_size=missing, auto_reload=missing,
-                bytecode_cache=missing):
+    def overlay(
+        self,
+        block_start_string=missing,
+        block_end_string=missing,
+        variable_start_string=missing,
+        variable_end_string=missing,
+        comment_start_string=missing,
+        comment_end_string=missing,
+        line_statement_prefix=missing,
+        line_comment_prefix=missing,
+        trim_blocks=missing,
+        lstrip_blocks=missing,
+        extensions=missing,
+        optimized=missing,
+        undefined=missing,
+        finalize=missing,
+        autoescape=missing,
+        loader=missing,
+        cache_size=missing,
+        auto_reload=missing,
+        bytecode_cache=missing,
+    ):
         """Create a new overlay environment that shares all the data with the
         current environment except for cache and the overridden attributes.
         Extensions cannot be removed for an overlayed environment.  An overlayed
@@ -402,7 +422,7 @@ class Environment(object):
         through.
         """
         args = dict(locals())
-        del args['self'], args['cache_size'], args['extensions']
+        del args["self"], args["cache_size"], args["extensions"]
 
         rv = object.__new__(self.__class__)
         rv.__dict__.update(self.__dict__)
@@ -430,8 +450,7 @@ class Environment(object):
 
     def iter_extensions(self):
         """Iterates over the extensions by priority."""
-        return iter(sorted(self.extensions.values(),
-                           key=lambda x: x.priority))
+        return iter(sorted(self.extensions.values(), key=lambda x: x.priority))
 
     def getitem(self, obj, argument):
         """Get an item or attribute of an object but prefer the item."""
@@ -463,8 +482,9 @@ class Environment(object):
         except (TypeError, LookupError, AttributeError):
             return self.undefined(obj=obj, name=attribute)
 
-    def call_filter(self, name, value, args=None, kwargs=None,
-                    context=None, eval_ctx=None):
+    def call_filter(
+        self, name, value, args=None, kwargs=None, context=None, eval_ctx=None
+    ):
         """Invokes a filter on a value the same way the compiler does it.
 
         Note that on Python 3 this might return a coroutine in case the
@@ -476,21 +496,22 @@ class Environment(object):
         """
         func = self.filters.get(name)
         if func is None:
-            fail_for_missing_callable('no filter named %r', name)
+            fail_for_missing_callable("no filter named %r", name)
         args = [value] + list(args or ())
-        if getattr(func, 'contextfilter', False):
+        if getattr(func, "contextfilter", False):
             if context is None:
-                raise TemplateRuntimeError('Attempted to invoke context '
-                                           'filter without context')
+                raise TemplateRuntimeError(
+                    "Attempted to invoke context filter without context"
+                )
             args.insert(0, context)
-        elif getattr(func, 'evalcontextfilter', False):
+        elif getattr(func, "evalcontextfilter", False):
             if eval_ctx is None:
                 if context is not None:
                     eval_ctx = context.eval_ctx
                 else:
                     eval_ctx = EvalContext(self)
             args.insert(0, eval_ctx)
-        elif getattr(func, 'environmentfilter', False):
+        elif getattr(func, "environmentfilter", False):
             args.insert(0, self)
         return func(*args, **(kwargs or {}))
 
@@ -501,7 +522,7 @@ class Environment(object):
         """
         func = self.tests.get(name)
         if func is None:
-            fail_for_missing_callable('no test named %r', name)
+            fail_for_missing_callable("no test named %r", name)
         return func(value, *(args or ()), **(kwargs or {}))
 
     @internalcode
@@ -544,8 +565,11 @@ class Environment(object):
         called for all parsing and compiling methods but *not* for :meth:`lex`
         because there you usually only want the actual source tokenized.
         """
-        return reduce(lambda s, e: e.preprocess(s, name, filename),
-                      self.iter_extensions(), text_type(source))
+        return reduce(
+            lambda s, e: e.preprocess(s, name, filename),
+            self.iter_extensions(),
+            text_type(source),
+        )
 
     def _tokenize(self, source, name, filename=None, state=None):
         """Called by the parser to do the preprocessing and filtering
@@ -565,8 +589,14 @@ class Environment(object):
 
         .. versionadded:: 2.5
         """
-        return generate(source, self, name, filename, defer_init=defer_init,
-                        optimized=self.optimized)
+        return generate(
+            source,
+            self,
+            name,
+            filename,
+            defer_init=defer_init,
+            optimized=self.optimized,
+        )
 
     def _compile(self, source, filename):
         """Internal hook that can be overridden to hook a different compile
@@ -574,11 +604,10 @@ class Environment(object):
 
         .. versionadded:: 2.5
         """
-        return compile(source, filename, 'exec')
+        return compile(source, filename, "exec")
 
     @internalcode
-    def compile(self, source, name=None, filename=None, raw=False,
-                defer_init=False):
+    def compile(self, source, name=None, filename=None, raw=False, defer_init=False):
         """Compile a node or template source code.  The `name` parameter is
         the load name of the template after it was joined using
         :meth:`join_path` if necessary, not the filename on the file system.
@@ -603,12 +632,11 @@ class Environment(object):
             if isinstance(source, string_types):
                 source_hint = source
                 source = self._parse(source, name, filename)
-            source = self._generate(source, name, filename,
-                                    defer_init=defer_init)
+            source = self._generate(source, name, filename, defer_init=defer_init)
             if raw:
                 return source
             if filename is None:
-                filename = '<template>'
+                filename = "<template>"
             else:
                 filename = encode_filename(filename)
             return self._compile(source, filename)
@@ -643,25 +671,32 @@ class Environment(object):
 
         .. versionadded:: 2.1
         """
-        parser = Parser(self, source, state='variable')
+        parser = Parser(self, source, state="variable")
         try:
             expr = parser.parse_expression()
             if not parser.stream.eos:
-                raise TemplateSyntaxError('chunk after expression',
-                                          parser.stream.current.lineno,
-                                          None, None)
+                raise TemplateSyntaxError(
+                    "chunk after expression", parser.stream.current.lineno, None, None
+                )
             expr.set_environment(self)
         except TemplateSyntaxError:
             if sys.exc_info() is not None:
                 self.handle_exception(source=source)
 
-        body = [nodes.Assign(nodes.Name('result', 'store'), expr, lineno=1)]
+        body = [nodes.Assign(nodes.Name("result", "store"), expr, lineno=1)]
         template = self.from_string(nodes.Template(body, lineno=1))
         return TemplateExpression(template, undefined_to_none)
 
-    def compile_templates(self, target, extensions=None, filter_func=None,
-                          zip='deflated', log_function=None,
-                          ignore_errors=True, py_compile=False):
+    def compile_templates(
+        self,
+        target,
+        extensions=None,
+        filter_func=None,
+        zip="deflated",
+        log_function=None,
+        ignore_errors=True,
+        py_compile=False,
+    ):
         """Finds all the templates the loader can find, compiles them
         and stores them in `target`.  If `zip` is `None`, instead of in a
         zipfile, the templates will be stored in a directory.
@@ -692,17 +727,18 @@ class Environment(object):
         if py_compile:
             if not PY2 or PYPY:
                 from warnings import warn
-                warn(Warning('py_compile has no effect on pypy or Python 3'))
+
+                warn(Warning("py_compile has no effect on pypy or Python 3"))
                 py_compile = False
             else:
                 import imp
                 import marshal
-                py_header = imp.get_magic() + \
-                    u'\xff\xff\xff\xff'.encode('iso-8859-15')
+
+                py_header = imp.get_magic() + u"\xff\xff\xff\xff".encode("iso-8859-15")
 
                 # Python 3.3 added a source filesize to the header
                 if sys.version_info >= (3, 3):
-                    py_header += u'\x00\x00\x00\x00'.encode('iso-8859-15')
+                    py_header += u"\x00\x00\x00\x00".encode("iso-8859-15")
 
         def write_file(filename, data):
             if zip:
@@ -718,8 +754,10 @@ class Environment(object):
 
         if zip is not None:
             from zipfile import ZipFile, ZipInfo, ZIP_DEFLATED, ZIP_STORED
-            zip_file = ZipFile(target, 'w', dict(deflated=ZIP_DEFLATED,
-                                                 stored=ZIP_STORED)[zip])
+
+            zip_file = ZipFile(
+                target, "w", dict(deflated=ZIP_DEFLATED, stored=ZIP_STORED)[zip]
+            )
             log_function('Compiling into Zip archive "%s"' % target)
         else:
             if not os.path.isdir(target):
@@ -741,10 +779,8 @@ class Environment(object):
 
                 if py_compile:
                     c = self._compile(code, encode_filename(filename))
-                    write_file(filename + 'c', py_header +
-                               marshal.dumps(c))
-                    log_function('Byte-compiled "%s" as %s' %
-                                 (name, filename + 'c'))
+                    write_file(filename + "c", py_header + marshal.dumps(c))
+                    log_function('Byte-compiled "%s" as %s' % (name, filename + "c"))
                 else:
                     write_file(filename, code)
                     log_function('Compiled "%s" as %s' % (name, filename))
@@ -752,7 +788,7 @@ class Environment(object):
             if zip:
                 zip_file.close()
 
-        log_function('Finished compiling templates')
+        log_function("Finished compiling templates")
 
     def list_templates(self, extensions=None, filter_func=None):
         """Returns a list of templates for this environment.  This requires
@@ -773,10 +809,10 @@ class Environment(object):
         x = self.loader.list_templates()
         if extensions is not None:
             if filter_func is not None:
-                raise TypeError('either extensions or filter_func '
-                                'can be passed, but not both')
-            filter_func = lambda x: '.' in x and \
-                                    x.rsplit('.', 1)[1] in extensions
+                raise TypeError(
+                    "either extensions or filter_func can be passed, but not both"
+                )
+            filter_func = lambda x: "." in x and x.rsplit(".", 1)[1] in extensions
         if filter_func is not None:
             x = list(ifilter(filter_func, x))
         return x
@@ -786,6 +822,7 @@ class Environment(object):
         rewritten exceptions or return a rendered traceback for the template.
         """
         from jinja2.debug import rewrite_traceback_stack
+
         reraise(*rewrite_traceback_stack(source=source))
 
     def join_path(self, template, parent):
@@ -803,12 +840,13 @@ class Environment(object):
     @internalcode
     def _load_template(self, name, globals):
         if self.loader is None:
-            raise TypeError('no loader for this environment specified')
+            raise TypeError("no loader for this environment specified")
         cache_key = (weakref.ref(self.loader), name)
         if self.cache is not None:
             template = self.cache.get(cache_key)
-            if template is not None and (not self.auto_reload or
-                                         template.is_up_to_date):
+            if template is not None and (
+                not self.auto_reload or template.is_up_to_date
+            ):
                 return template
         template = self.loader.load(self, name, globals)
         if self.cache is not None:
@@ -859,8 +897,9 @@ class Environment(object):
             names._fail_with_undefined_error()
 
         if not names:
-            raise TemplatesNotFound(message=u'Tried to select from an empty list '
-                                            u'of templates.')
+            raise TemplatesNotFound(
+                message=u"Tried to select from an empty list " u"of templates."
+            )
         globals = self.make_globals(globals)
         for name in names:
             if isinstance(name, Template):
@@ -874,8 +913,7 @@ class Environment(object):
         raise TemplatesNotFound(names)
 
     @internalcode
-    def get_or_select_template(self, template_name_or_list,
-                               parent=None, globals=None):
+    def get_or_select_template(self, template_name_or_list, parent=None, globals=None):
         """Does a typecheck and dispatches to :meth:`select_template`
         if an iterable of template names is given, otherwise to
         :meth:`get_template`.
@@ -937,33 +975,53 @@ class Template(object):
     #: rather than through an existing environment.
     environment_class = Environment
 
-    def __new__(cls, source,
-                block_start_string=BLOCK_START_STRING,
-                block_end_string=BLOCK_END_STRING,
-                variable_start_string=VARIABLE_START_STRING,
-                variable_end_string=VARIABLE_END_STRING,
-                comment_start_string=COMMENT_START_STRING,
-                comment_end_string=COMMENT_END_STRING,
-                line_statement_prefix=LINE_STATEMENT_PREFIX,
-                line_comment_prefix=LINE_COMMENT_PREFIX,
-                trim_blocks=TRIM_BLOCKS,
-                lstrip_blocks=LSTRIP_BLOCKS,
-                newline_sequence=NEWLINE_SEQUENCE,
-                keep_trailing_newline=KEEP_TRAILING_NEWLINE,
-                extensions=(),
-                optimized=True,
-                undefined=Undefined,
-                finalize=None,
-                autoescape=False,
-                enable_async=False):
+    def __new__(
+        cls,
+        source,
+        block_start_string=BLOCK_START_STRING,
+        block_end_string=BLOCK_END_STRING,
+        variable_start_string=VARIABLE_START_STRING,
+        variable_end_string=VARIABLE_END_STRING,
+        comment_start_string=COMMENT_START_STRING,
+        comment_end_string=COMMENT_END_STRING,
+        line_statement_prefix=LINE_STATEMENT_PREFIX,
+        line_comment_prefix=LINE_COMMENT_PREFIX,
+        trim_blocks=TRIM_BLOCKS,
+        lstrip_blocks=LSTRIP_BLOCKS,
+        newline_sequence=NEWLINE_SEQUENCE,
+        keep_trailing_newline=KEEP_TRAILING_NEWLINE,
+        extensions=(),
+        optimized=True,
+        undefined=Undefined,
+        finalize=None,
+        autoescape=False,
+        enable_async=False,
+    ):
         env = get_spontaneous_environment(
             cls.environment_class,
-            block_start_string, block_end_string, variable_start_string,
-            variable_end_string, comment_start_string, comment_end_string,
-            line_statement_prefix, line_comment_prefix, trim_blocks,
-            lstrip_blocks, newline_sequence, keep_trailing_newline,
-            frozenset(extensions), optimized, undefined, finalize, autoescape,
-            None, 0, False, None, enable_async)
+            block_start_string,
+            block_end_string,
+            variable_start_string,
+            variable_end_string,
+            comment_start_string,
+            comment_end_string,
+            line_statement_prefix,
+            line_comment_prefix,
+            trim_blocks,
+            lstrip_blocks,
+            newline_sequence,
+            keep_trailing_newline,
+            frozenset(extensions),
+            optimized,
+            undefined,
+            finalize,
+            autoescape,
+            None,
+            0,
+            False,
+            None,
+            enable_async,
+        )
         return env.from_string(source, template_class=cls)
 
     @classmethod
@@ -971,10 +1029,7 @@ class Template(object):
         """Creates a template object from compiled code and the globals.  This
         is used by the loaders and environment to create a template object.
         """
-        namespace = {
-            'environment':  environment,
-            '__file__':     code.co_filename
-        }
+        namespace = {"environment": environment, "__file__": code.co_filename}
         exec(code, namespace)
         rv = cls._from_namespace(environment, namespace, globals)
         rv._uptodate = uptodate
@@ -994,21 +1049,21 @@ class Template(object):
         t = object.__new__(cls)
         t.environment = environment
         t.globals = globals
-        t.name = namespace['name']
-        t.filename = namespace['__file__']
-        t.blocks = namespace['blocks']
+        t.name = namespace["name"]
+        t.filename = namespace["__file__"]
+        t.blocks = namespace["blocks"]
 
         # render function and module
-        t.root_render_func = namespace['root']
+        t.root_render_func = namespace["root"]
         t._module = None
 
         # debug and loader helpers
-        t._debug_info = namespace['debug_info']
+        t._debug_info = namespace["debug_info"]
         t._uptodate = None
 
         # store the reference
-        namespace['environment'] = environment
-        namespace['__jinja_template__'] = t
+        namespace["environment"] = environment
+        namespace["__jinja_template__"] = t
 
         return t
 
@@ -1038,8 +1093,9 @@ class Template(object):
             await template.render_async(knights='that say nih; asynchronously')
         """
         # see asyncsupport for the actual implementation
-        raise NotImplementedError('This feature is not available for this '
-                                  'version of Python')
+        raise NotImplementedError(
+            "This feature is not available for this version of Python"
+        )
 
     def stream(self, *args, **kwargs):
         """Works exactly like :meth:`generate` but returns a
@@ -1067,8 +1123,9 @@ class Template(object):
         returns an async iterator instead.
         """
         # see asyncsupport for the actual implementation
-        raise NotImplementedError('This feature is not available for this '
-                                  'version of Python')
+        raise NotImplementedError(
+            "This feature is not available for this version of Python"
+        )
 
     def new_context(self, vars=None, shared=False, locals=None):
         """Create a new :class:`Context` for this template.  The vars
@@ -1078,8 +1135,9 @@ class Template(object):
 
         `locals` can be a dict of local variables for internal usage.
         """
-        return new_context(self.environment, self.name, self.blocks,
-                           vars, shared, self.globals, locals)
+        return new_context(
+            self.environment, self.name, self.blocks, vars, shared, self.globals, locals
+        )
 
     def make_module(self, vars=None, shared=False, locals=None):
         """This method works like the :attr:`module` attribute when called
@@ -1097,8 +1155,9 @@ class Template(object):
         becomes unavailable in async mode.
         """
         # see asyncsupport for the actual implementation
-        raise NotImplementedError('This feature is not available for this '
-                                  'version of Python')
+        raise NotImplementedError(
+            "This feature is not available for this version of Python"
+        )
 
     @internalcode
     def _get_default_module(self):
@@ -1143,16 +1202,15 @@ class Template(object):
     def debug_info(self):
         """The debug info mapping."""
         if self._debug_info:
-            return [tuple(imap(int, x.split('='))) for x in
-                    self._debug_info.split('&')]
+            return [tuple(imap(int, x.split("="))) for x in self._debug_info.split("&")]
         return []
 
     def __repr__(self):
         if self.name is None:
-            name = 'memory:%x' % id(self)
+            name = "memory:%x" % id(self)
         else:
             name = repr(self.name)
-        return '<%s %s>' % (self.__class__.__name__, name)
+        return "<%s %s>" % (self.__class__.__name__, name)
 
 
 @implements_to_string
@@ -1165,10 +1223,12 @@ class TemplateModule(object):
     def __init__(self, template, context, body_stream=None):
         if body_stream is None:
             if context.environment.is_async:
-                raise RuntimeError('Async mode requires a body stream '
-                                   'to be passed to a template module.  Use '
-                                   'the async methods of the API you are '
-                                   'using.')
+                raise RuntimeError(
+                    "Async mode requires a body stream "
+                    "to be passed to a template module.  Use "
+                    "the async methods of the API you are "
+                    "using."
+                )
             body_stream = list(template.root_render_func(context))
         self._body_stream = body_stream
         self.__dict__.update(context.get_exported())
@@ -1182,10 +1242,10 @@ class TemplateModule(object):
 
     def __repr__(self):
         if self.__name__ is None:
-            name = 'memory:%x' % id(self)
+            name = "memory:%x" % id(self)
         else:
             name = repr(self.__name__)
-        return '<%s %s>' % (self.__class__.__name__, name)
+        return "<%s %s>" % (self.__class__.__name__, name)
 
 
 class TemplateExpression(object):
@@ -1201,7 +1261,7 @@ class TemplateExpression(object):
     def __call__(self, *args, **kwargs):
         context = self._template.new_context(dict(*args, **kwargs))
         consume(self._template.root_render_func(context))
-        rv = context.vars['result']
+        rv = context.vars["result"]
         if self._undefined_to_none and isinstance(rv, Undefined):
             rv = None
         return rv
@@ -1223,7 +1283,7 @@ class TemplateStream(object):
         self._gen = gen
         self.disable_buffering()
 
-    def dump(self, fp, encoding=None, errors='strict'):
+    def dump(self, fp, encoding=None, errors="strict"):
         """Dump the complete stream into a file or file-like object.
         Per default unicode strings are written, if you want to encode
         before writing specify an `encoding`.
@@ -1235,15 +1295,15 @@ class TemplateStream(object):
         close = False
         if isinstance(fp, string_types):
             if encoding is None:
-                encoding = 'utf-8'
-            fp = open(fp, 'wb')
+                encoding = "utf-8"
+            fp = open(fp, "wb")
             close = True
         try:
             if encoding is not None:
                 iterable = (x.encode(encoding, errors) for x in self)
             else:
                 iterable = self
-            if hasattr(fp, 'writelines'):
+            if hasattr(fp, "writelines"):
                 fp.writelines(iterable)
             else:
                 for item in iterable:
@@ -1279,7 +1339,7 @@ class TemplateStream(object):
     def enable_buffering(self, size=5):
         """Enable buffering.  Buffer `size` items before yielding them."""
         if size <= 1:
-            raise ValueError('buffer size too small')
+            raise ValueError("buffer size too small")
 
         self.buffered = True
         self._next = partial(next, self._buffered_generator(size))
index 6ceea308941f023f95cb0530951a9f77b457c776..103837034ebca1b7d09a3c9113f02f6337ecb88e 100644 (file)
@@ -18,9 +18,10 @@ class TemplateError(Exception):
     """Baseclass for all template errors."""
 
     if PY2:
+
         def __init__(self, message=None):
             if message is not None:
-                message = text_type(message).encode('utf-8')
+                message = text_type(message).encode("utf-8")
             Exception.__init__(self, message)
 
         @property
@@ -28,11 +29,13 @@ class TemplateError(Exception):
             if self.args:
                 message = self.args[0]
                 if message is not None:
-                    return message.decode('utf-8', 'replace')
+                    return message.decode("utf-8", "replace")
 
         def __unicode__(self):
-            return self.message or u''
+            return self.message or u""
+
     else:
+
         def __init__(self, message=None):
             Exception.__init__(self, message)
 
@@ -100,8 +103,9 @@ class TemplatesNotFound(TemplateNotFound):
                 else:
                     parts.append(name)
 
-            message = u'none of the templates given were found: ' + \
-                      u', '.join(imap(text_type, parts))
+            message = u"none of the templates given were found: " + u", ".join(
+                imap(text_type, parts)
+            )
         TemplateNotFound.__init__(self, names and names[-1] or None, message)
         self.templates = list(names)
 
@@ -127,11 +131,11 @@ class TemplateSyntaxError(TemplateError):
             return self.message
 
         # otherwise attach some stuff
-        location = 'line %d' % self.lineno
+        location = "line %d" % self.lineno
         name = self.filename or self.name
         if name:
             location = 'File "%s", %s' % (name, location)
-        lines = [self.message, '  ' + location]
+        lines = [self.message, "  " + location]
 
         # if the source is set, add the line to the output
         if self.source is not None:
@@ -140,9 +144,9 @@ class TemplateSyntaxError(TemplateError):
             except IndexError:
                 line = None
             if line:
-                lines.append('    ' + line.strip())
+                lines.append("    " + line.strip())
 
-        return u'\n'.join(lines)
+        return u"\n".join(lines)
 
     def __reduce__(self):
         # https://bugs.python.org/issue1692335 Exceptions that take
index 433277aa531e8d4b8c41acd4b955b40821f78eb6..4891c9cdfea3189bfa6f8de17522fcc587d3be4e 100644 (file)
@@ -46,7 +46,7 @@ from .utils import Markup
 # the only real useful gettext functions for a Jinja template.  Note
 # that ugettext must be assigned to gettext as Jinja doesn't support
 # non unicode strings.
-GETTEXT_FUNCTIONS = ('_', 'gettext', 'ngettext')
+GETTEXT_FUNCTIONS = ("_", "gettext", "ngettext")
 
 
 class ExtensionRegistry(type):
@@ -54,7 +54,7 @@ class ExtensionRegistry(type):
 
     def __new__(cls, name, bases, d):
         rv = type.__new__(cls, name, bases, d)
-        rv.identifier = rv.__module__ + '.' + rv.__name__
+        rv.identifier = rv.__module__ + "." + rv.__name__
         return rv
 
 
@@ -134,8 +134,9 @@ class Extension(with_metaclass(ExtensionRegistry, object)):
         """
         return nodes.ExtensionAttribute(self.identifier, name, lineno=lineno)
 
-    def call_method(self, name, args=None, kwargs=None, dyn_args=None,
-                    dyn_kwargs=None, lineno=None):
+    def call_method(
+        self, name, args=None, kwargs=None, dyn_args=None, dyn_kwargs=None, lineno=None
+    ):
         """Call a method of the extension.  This is a shortcut for
         :meth:`attr` + :class:`jinja2.nodes.Call`.
         """
@@ -143,13 +144,19 @@ class Extension(with_metaclass(ExtensionRegistry, object)):
             args = []
         if kwargs is None:
             kwargs = []
-        return nodes.Call(self.attr(name, lineno=lineno), args, kwargs,
-                          dyn_args, dyn_kwargs, lineno=lineno)
+        return nodes.Call(
+            self.attr(name, lineno=lineno),
+            args,
+            kwargs,
+            dyn_args,
+            dyn_kwargs,
+            lineno=lineno,
+        )
 
 
 @contextfunction
 def _gettext_alias(__context, *args, **kwargs):
-    return __context.call(__context.resolve('gettext'), *args, **kwargs)
+    return __context.call(__context.resolve("gettext"), *args, **kwargs)
 
 
 def _make_new_gettext(func):
@@ -162,24 +169,27 @@ def _make_new_gettext(func):
         # variables. This makes translation strings more consistent
         # and predictable. This requires escaping
         return rv % variables
+
     return gettext
 
 
 def _make_new_ngettext(func):
     @contextfunction
     def ngettext(__context, __singular, __plural, __num, **variables):
-        variables.setdefault('num', __num)
+        variables.setdefault("num", __num)
         rv = __context.call(func, __singular, __plural, __num)
         if __context.eval_ctx.autoescape:
             rv = Markup(rv)
         # Always treat as a format string, see gettext comment above.
         return rv % variables
+
     return ngettext
 
 
 class InternationalizationExtension(Extension):
     """This extension adds gettext support to Jinja."""
-    tags = {'trans'}
+
+    tags = {"trans"}
 
     # TODO: the i18n extension is currently reevaluating values in a few
     # situations.  Take this example:
@@ -190,30 +200,28 @@ class InternationalizationExtension(Extension):
 
     def __init__(self, environment):
         Extension.__init__(self, environment)
-        environment.globals['_'] = _gettext_alias
+        environment.globals["_"] = _gettext_alias
         environment.extend(
             install_gettext_translations=self._install,
             install_null_translations=self._install_null,
             install_gettext_callables=self._install_callables,
             uninstall_gettext_translations=self._uninstall,
             extract_translations=self._extract,
-            newstyle_gettext=False
+            newstyle_gettext=False,
         )
 
     def _install(self, translations, newstyle=None):
-        gettext = getattr(translations, 'ugettext', None)
+        gettext = getattr(translations, "ugettext", None)
         if gettext is None:
             gettext = translations.gettext
-        ngettext = getattr(translations, 'ungettext', None)
+        ngettext = getattr(translations, "ungettext", None)
         if ngettext is None:
             ngettext = translations.ngettext
         self._install_callables(gettext, ngettext, newstyle)
 
     def _install_null(self, newstyle=None):
         self._install_callables(
-            lambda x: x,
-            lambda s, p, n: (n != 1 and (p,) or (s,))[0],
-            newstyle
+            lambda x: x, lambda s, p, n: (n != 1 and (p,) or (s,))[0], newstyle
         )
 
     def _install_callables(self, gettext, ngettext, newstyle=None):
@@ -222,13 +230,10 @@ class InternationalizationExtension(Extension):
         if self.environment.newstyle_gettext:
             gettext = _make_new_gettext(gettext)
             ngettext = _make_new_ngettext(ngettext)
-        self.environment.globals.update(
-            gettext=gettext,
-            ngettext=ngettext
-        )
+        self.environment.globals.update(gettext=gettext, ngettext=ngettext)
 
     def _uninstall(self, translations):
-        for key in 'gettext', 'ngettext':
+        for key in "gettext", "ngettext":
             self.environment.globals.pop(key, None)
 
     def _extract(self, source, gettext_functions=GETTEXT_FUNCTIONS):
@@ -248,41 +253,44 @@ class InternationalizationExtension(Extension):
         plural_expr_assignment = None
         variables = {}
         trimmed = None
-        while parser.stream.current.type != 'block_end':
+        while parser.stream.current.type != "block_end":
             if variables:
-                parser.stream.expect('comma')
+                parser.stream.expect("comma")
 
             # skip colon for python compatibility
-            if parser.stream.skip_if('colon'):
+            if parser.stream.skip_if("colon"):
                 break
 
-            name = parser.stream.expect('name')
+            name = parser.stream.expect("name")
             if name.value in variables:
-                parser.fail('translatable variable %r defined twice.' %
-                            name.value, name.lineno,
-                            exc=TemplateAssertionError)
+                parser.fail(
+                    "translatable variable %r defined twice." % name.value,
+                    name.lineno,
+                    exc=TemplateAssertionError,
+                )
 
             # expressions
-            if parser.stream.current.type == 'assign':
+            if parser.stream.current.type == "assign":
                 next(parser.stream)
                 variables[name.value] = var = parser.parse_expression()
-            elif trimmed is None and name.value in ('trimmed', 'notrimmed'):
-                trimmed = name.value == 'trimmed'
+            elif trimmed is None and name.value in ("trimmed", "notrimmed"):
+                trimmed = name.value == "trimmed"
                 continue
             else:
-                variables[name.value] = var = nodes.Name(name.value, 'load')
+                variables[name.value] = var = nodes.Name(name.value, "load")
 
             if plural_expr is None:
                 if isinstance(var, nodes.Call):
-                    plural_expr = nodes.Name('_trans', 'load')
+                    plural_expr = nodes.Name("_trans", "load")
                     variables[name.value] = plural_expr
                     plural_expr_assignment = nodes.Assign(
-                        nodes.Name('_trans', 'store'), var)
+                        nodes.Name("_trans", "store"), var
+                    )
                 else:
                     plural_expr = var
-                num_called_num = name.value == 'num'
+                num_called_num = name.value == "num"
 
-        parser.stream.expect('block_end')
+        parser.stream.expect("block_end")
 
         plural = None
         have_plural = False
@@ -293,22 +301,24 @@ class InternationalizationExtension(Extension):
         if singular_names:
             referenced.update(singular_names)
             if plural_expr is None:
-                plural_expr = nodes.Name(singular_names[0], 'load')
-                num_called_num = singular_names[0] == 'num'
+                plural_expr = nodes.Name(singular_names[0], "load")
+                num_called_num = singular_names[0] == "num"
 
         # if we have a pluralize block, we parse that too
-        if parser.stream.current.test('name:pluralize'):
+        if parser.stream.current.test("name:pluralize"):
             have_plural = True
             next(parser.stream)
-            if parser.stream.current.type != 'block_end':
-                name = parser.stream.expect('name')
+            if parser.stream.current.type != "block_end":
+                name = parser.stream.expect("name")
                 if name.value not in variables:
-                    parser.fail('unknown variable %r for pluralization' %
-                                name.value, name.lineno,
-                                exc=TemplateAssertionError)
+                    parser.fail(
+                        "unknown variable %r for pluralization" % name.value,
+                        name.lineno,
+                        exc=TemplateAssertionError,
+                    )
                 plural_expr = variables[name.value]
-                num_called_num = name.value == 'num'
-            parser.stream.expect('block_end')
+                num_called_num = name.value == "num"
+            parser.stream.expect("block_end")
             plural_names, plural = self._parse_block(parser, False)
             next(parser.stream)
             referenced.update(plural_names)
@@ -318,88 +328,97 @@ class InternationalizationExtension(Extension):
         # register free names as simple name expressions
         for var in referenced:
             if var not in variables:
-                variables[var] = nodes.Name(var, 'load')
+                variables[var] = nodes.Name(var, "load")
 
         if not have_plural:
             plural_expr = None
         elif plural_expr is None:
-            parser.fail('pluralize without variables', lineno)
+            parser.fail("pluralize without variables", lineno)
 
         if trimmed is None:
-            trimmed = self.environment.policies['ext.i18n.trimmed']
+            trimmed = self.environment.policies["ext.i18n.trimmed"]
         if trimmed:
             singular = self._trim_whitespace(singular)
             if plural:
                 plural = self._trim_whitespace(plural)
 
-        node = self._make_node(singular, plural, variables, plural_expr,
-                               bool(referenced),
-                               num_called_num and have_plural)
+        node = self._make_node(
+            singular,
+            plural,
+            variables,
+            plural_expr,
+            bool(referenced),
+            num_called_num and have_plural,
+        )
         node.set_lineno(lineno)
         if plural_expr_assignment is not None:
             return [plural_expr_assignment, node]
         else:
             return node
 
-    def _trim_whitespace(self, string, _ws_re=re.compile(r'\s*\n\s*')):
-        return _ws_re.sub(' ', string.strip())
+    def _trim_whitespace(self, string, _ws_re=re.compile(r"\s*\n\s*")):
+        return _ws_re.sub(" ", string.strip())
 
     def _parse_block(self, parser, allow_pluralize):
         """Parse until the next block tag with a given name."""
         referenced = []
         buf = []
         while 1:
-            if parser.stream.current.type == 'data':
-                buf.append(parser.stream.current.value.replace('%', '%%'))
+            if parser.stream.current.type == "data":
+                buf.append(parser.stream.current.value.replace("%", "%%"))
                 next(parser.stream)
-            elif parser.stream.current.type == 'variable_begin':
+            elif parser.stream.current.type == "variable_begin":
                 next(parser.stream)
-                name = parser.stream.expect('name').value
+                name = parser.stream.expect("name").value
                 referenced.append(name)
-                buf.append('%%(%s)s' % name)
-                parser.stream.expect('variable_end')
-            elif parser.stream.current.type == 'block_begin':
+                buf.append("%%(%s)s" % name)
+                parser.stream.expect("variable_end")
+            elif parser.stream.current.type == "block_begin":
                 next(parser.stream)
-                if parser.stream.current.test('name:endtrans'):
+                if parser.stream.current.test("name:endtrans"):
                     break
-                elif parser.stream.current.test('name:pluralize'):
+                elif parser.stream.current.test("name:pluralize"):
                     if allow_pluralize:
                         break
-                    parser.fail('a translatable section can have only one '
-                                'pluralize section')
-                parser.fail('control structures in translatable sections are '
-                            'not allowed')
+                    parser.fail(
+                        "a translatable section can have only one pluralize section"
+                    )
+                parser.fail(
+                    "control structures in translatable sections are not allowed"
+                )
             elif parser.stream.eos:
-                parser.fail('unclosed translation block')
+                parser.fail("unclosed translation block")
             else:
-                assert False, 'internal parser error'
+                assert False, "internal parser error"
 
         return referenced, concat(buf)
 
-    def _make_node(self, singular, plural, variables, plural_expr,
-                   vars_referenced, num_called_num):
+    def _make_node(
+        self, singular, plural, variables, plural_expr, vars_referenced, num_called_num
+    ):
         """Generates a useful node from the data provided."""
         # no variables referenced?  no need to escape for old style
         # gettext invocations only if there are vars.
         if not vars_referenced and not self.environment.newstyle_gettext:
-            singular = singular.replace('%%', '%')
+            singular = singular.replace("%%", "%")
             if plural:
-                plural = plural.replace('%%', '%')
+                plural = plural.replace("%%", "%")
 
         # singular only:
         if plural_expr is None:
-            gettext = nodes.Name('gettext', 'load')
-            node = nodes.Call(gettext, [nodes.Const(singular)],
-                              [], None, None)
+            gettext = nodes.Name("gettext", "load")
+            node = nodes.Call(gettext, [nodes.Const(singular)], [], None, None)
 
         # singular and plural
         else:
-            ngettext = nodes.Name('ngettext', 'load')
-            node = nodes.Call(ngettext, [
-                nodes.Const(singular),
-                nodes.Const(plural),
-                plural_expr
-            ], [], None, None)
+            ngettext = nodes.Name("ngettext", "load")
+            node = nodes.Call(
+                ngettext,
+                [nodes.Const(singular), nodes.Const(plural), plural_expr],
+                [],
+                None,
+                None,
+            )
 
         # in case newstyle gettext is used, the method is powerful
         # enough to handle the variable expansion and autoescape
@@ -408,7 +427,7 @@ class InternationalizationExtension(Extension):
             for key, value in iteritems(variables):
                 # the function adds that later anyways in case num was
                 # called num, so just skip it.
-                if num_called_num and key == 'num':
+                if num_called_num and key == "num":
                     continue
                 node.kwargs.append(nodes.Keyword(key, value))
 
@@ -418,10 +437,15 @@ class InternationalizationExtension(Extension):
             # environment with autoescaping turned on
             node = nodes.MarkSafeIfAutoescape(node)
             if variables:
-                node = nodes.Mod(node, nodes.Dict([
-                    nodes.Pair(nodes.Const(key), value)
-                    for key, value in variables.items()
-                ]))
+                node = nodes.Mod(
+                    node,
+                    nodes.Dict(
+                        [
+                            nodes.Pair(nodes.Const(key), value)
+                            for key, value in variables.items()
+                        ]
+                    ),
+                )
         return nodes.Output([node])
 
 
@@ -429,7 +453,8 @@ class ExprStmtExtension(Extension):
     """Adds a `do` tag to Jinja that works like the print statement just
     that it doesn't print the return value.
     """
-    tags = set(['do'])
+
+    tags = set(["do"])
 
     def parse(self, parser):
         node = nodes.ExprStmt(lineno=next(parser.stream).lineno)
@@ -439,11 +464,12 @@ class ExprStmtExtension(Extension):
 
 class LoopControlExtension(Extension):
     """Adds break and continue to the template engine."""
-    tags = set(['break', 'continue'])
+
+    tags = set(["break", "continue"])
 
     def parse(self, parser):
         token = next(parser.stream)
-        if token.value == 'break':
+        if token.value == "break":
             return nodes.Break(lineno=token.lineno)
         return nodes.Continue(lineno=token.lineno)
 
@@ -476,7 +502,8 @@ class DebugExtension(Extension):
 
     .. versionadded:: 2.11.0
     """
-    tags = {'debug'}
+
+    tags = {"debug"}
 
     def parse(self, parser):
         lineno = parser.stream.expect("name:debug").lineno
@@ -498,8 +525,7 @@ class DebugExtension(Extension):
             return pprint.pformat(result, depth=3)
 
 
-def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
-                     babel_style=True):
+def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS, babel_style=True):
     """Extract localizable strings from the given template node.  Per
     default this function returns matches in babel style that means non string
     parameters as well as keyword arguments are returned as `None`.  This
@@ -535,14 +561,15 @@ def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS,
     extraction interface or extract comments yourself.
     """
     for node in node.find_all(nodes.Call):
-        if not isinstance(node.node, nodes.Name) or \
-           node.node.name not in gettext_functions:
+        if (
+            not isinstance(node.node, nodes.Name)
+            or node.node.name not in gettext_functions
+        ):
             continue
 
         strings = []
         for arg in node.args:
-            if isinstance(arg, nodes.Const) and \
-               isinstance(arg.value, string_types):
+            if isinstance(arg, nodes.Const) and isinstance(arg.value, string_types):
                 strings.append(arg.value)
             else:
                 strings.append(None)
@@ -581,9 +608,10 @@ class _CommentFinder(object):
 
     def find_backwards(self, offset):
         try:
-            for _, token_type, token_value in \
-                    reversed(self.tokens[self.offset:offset]):
-                if token_type in ('comment', 'linecomment'):
+            for _, token_type, token_value in reversed(
+                self.tokens[self.offset : offset]
+            ):
+                if token_type in ("comment", "linecomment"):
                     try:
                         prefix, comment = token_value.split(None, 1)
                     except ValueError:
@@ -597,7 +625,7 @@ class _CommentFinder(object):
     def find_comments(self, lineno):
         if not self.comment_tags or self.last_lineno > lineno:
             return []
-        for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset:]):
+        for idx, (token_lineno, _, _) in enumerate(self.tokens[self.offset :]):
             if token_lineno > lineno:
                 return self.find_backwards(self.offset + idx)
         return self.find_backwards(len(self.tokens))
@@ -632,7 +660,7 @@ def babel_extract(fileobj, keywords, comment_tags, options):
              (comments will be empty currently)
     """
     extensions = set()
-    for extension in options.get('extensions', '').split(','):
+    for extension in options.get("extensions", "").split(","):
         extension = extension.strip()
         if not extension:
             continue
@@ -641,34 +669,33 @@ def babel_extract(fileobj, keywords, comment_tags, options):
         extensions.add(InternationalizationExtension)
 
     def getbool(options, key, default=False):
-        return options.get(key, str(default)).lower() in \
-            ('1', 'on', 'yes', 'true')
+        return options.get(key, str(default)).lower() in ("1", "on", "yes", "true")
 
-    silent = getbool(options, 'silent', True)
+    silent = getbool(options, "silent", True)
     environment = Environment(
-        options.get('block_start_string', BLOCK_START_STRING),
-        options.get('block_end_string', BLOCK_END_STRING),
-        options.get('variable_start_string', VARIABLE_START_STRING),
-        options.get('variable_end_string', VARIABLE_END_STRING),
-        options.get('comment_start_string', COMMENT_START_STRING),
-        options.get('comment_end_string', COMMENT_END_STRING),
-        options.get('line_statement_prefix') or LINE_STATEMENT_PREFIX,
-        options.get('line_comment_prefix') or LINE_COMMENT_PREFIX,
-        getbool(options, 'trim_blocks', TRIM_BLOCKS),
-        getbool(options, 'lstrip_blocks', LSTRIP_BLOCKS),
+        options.get("block_start_string", BLOCK_START_STRING),
+        options.get("block_end_string", BLOCK_END_STRING),
+        options.get("variable_start_string", VARIABLE_START_STRING),
+        options.get("variable_end_string", VARIABLE_END_STRING),
+        options.get("comment_start_string", COMMENT_START_STRING),
+        options.get("comment_end_string", COMMENT_END_STRING),
+        options.get("line_statement_prefix") or LINE_STATEMENT_PREFIX,
+        options.get("line_comment_prefix") or LINE_COMMENT_PREFIX,
+        getbool(options, "trim_blocks", TRIM_BLOCKS),
+        getbool(options, "lstrip_blocks", LSTRIP_BLOCKS),
         NEWLINE_SEQUENCE,
-        getbool(options, 'keep_trailing_newline', KEEP_TRAILING_NEWLINE),
+        getbool(options, "keep_trailing_newline", KEEP_TRAILING_NEWLINE),
         frozenset(extensions),
         cache_size=0,
-        auto_reload=False
+        auto_reload=False,
     )
 
-    if getbool(options, 'trimmed'):
-        environment.policies['ext.i18n.trimmed'] = True
-    if getbool(options, 'newstyle_gettext'):
+    if getbool(options, "trimmed"):
+        environment.policies["ext.i18n.trimmed"] = True
+    if getbool(options, "newstyle_gettext"):
         environment.newstyle_gettext = True
 
-    source = fileobj.read().decode(options.get('encoding', 'utf-8'))
+    source = fileobj.read().decode(options.get("encoding", "utf-8"))
     try:
         node = environment.parse(source)
         tokens = list(environment.lex(environment.preprocess(source)))
index 8bd389c6cfdc1b59cccb04320202a1229652c3f0..c7a2f39b8e45f7f54873fad007428c88ab0a4f03 100644 (file)
@@ -31,8 +31,8 @@ from .utils import soft_unicode
 from .utils import unicode_urlencode
 from .utils import urlize
 
-_word_re = re.compile(r'\w+', re.UNICODE)
-_word_beginning_split_re = re.compile(r'([-\s\(\{\[\<]+)', re.UNICODE)
+_word_re = re.compile(r"\w+", re.UNICODE)
+_word_beginning_split_re = re.compile(r"([-\s\(\{\[\<]+)", re.UNICODE)
 
 
 def contextfilter(f):
@@ -102,8 +102,12 @@ def make_multi_attrgetter(environment, attribute, postprocess=None):
 
     Examples of attribute: "attr1,attr2", "attr1.inner1.0,attr2.inner2.0", etc.
     """
-    attribute_parts = attribute.split(',') if isinstance(attribute, string_types) else [attribute]
-    attribute = [_prepare_attribute_parts(attribute_part) for attribute_part in attribute_parts]
+    attribute_parts = (
+        attribute.split(",") if isinstance(attribute, string_types) else [attribute]
+    )
+    attribute = [
+        _prepare_attribute_parts(attribute_part) for attribute_part in attribute_parts
+    ]
 
     def attrgetter(item):
         items = [None] * len(attribute)
@@ -125,14 +129,14 @@ def _prepare_attribute_parts(attr):
     if attr is None:
         return []
     elif isinstance(attr, string_types):
-        return [int(x) if x.isdigit() else x for x in attr.split('.')]
+        return [int(x) if x.isdigit() else x for x in attr.split(".")]
     else:
         return [attr]
 
 
 def do_forceescape(value):
     """Enforce HTML escaping.  This will probably double escape variables."""
-    if hasattr(value, '__html__'):
+    if hasattr(value, "__html__"):
         value = value.__html__()
     return escape(text_type(value))
 
@@ -187,8 +191,11 @@ def do_replace(eval_ctx, s, old, new, count=None):
         count = -1
     if not eval_ctx.autoescape:
         return text_type(s).replace(text_type(old), text_type(new), count)
-    if hasattr(old, '__html__') or hasattr(new, '__html__') and \
-       not hasattr(s, '__html__'):
+    if (
+        hasattr(old, "__html__")
+        or hasattr(new, "__html__")
+        and not hasattr(s, "__html__")
+    ):
         s = escape(s)
     else:
         s = soft_unicode(s)
@@ -229,13 +236,13 @@ def do_xmlattr(_eval_ctx, d, autospace=True):
     As you can see it automatically prepends a space in front of the item
     if the filter returned something unless the second parameter is false.
     """
-    rv = u' '.join(
+    rv = u" ".join(
         u'%s="%s"' % (escape(key), escape(value))
         for key, value in iteritems(d)
         if value is not None and not isinstance(value, Undefined)
     )
     if autospace and rv:
-        rv = u' ' + rv
+        rv = u" " + rv
     if _eval_ctx.autoescape:
         rv = Markup(rv)
     return rv
@@ -252,13 +259,16 @@ def do_title(s):
     """Return a titlecased version of the value. I.e. words will start with
     uppercase letters, all remaining characters are lowercase.
     """
-    return ''.join(
-        [item[0].upper() + item[1:].lower()
-         for item in _word_beginning_split_re.split(soft_unicode(s))
-         if item])
+    return "".join(
+        [
+            item[0].upper() + item[1:].lower()
+            for item in _word_beginning_split_re.split(soft_unicode(s))
+            if item
+        ]
+    )
 
 
-def do_dictsort(value, case_sensitive=False, by='key', reverse=False):
+def do_dictsort(value, case_sensitive=False, by="key", reverse=False):
     """Sort a dict and yield (key, value) pairs. Because python dicts are
     unsorted you may want to use this function to order them by either
     key or value:
@@ -277,14 +287,12 @@ def do_dictsort(value, case_sensitive=False, by='key', reverse=False):
         {% for item in mydict|dictsort(false, 'value') %}
             sort the dict by value, case insensitive
     """
-    if by == 'key':
+    if by == "key":
         pos = 0
-    elif by == 'value':
+    elif by == "value":
         pos = 1
     else:
-        raise FilterArgumentError(
-            'You can only sort by either "key" or "value"'
-        )
+        raise FilterArgumentError('You can only sort by either "key" or "value"')
 
     def sort_func(item):
         value = item[pos]
@@ -341,8 +349,7 @@ def do_sort(environment, value, reverse=False, case_sensitive=False, attribute=N
        The ``attribute`` parameter was added.
     """
     key_func = make_multi_attrgetter(
-        environment, attribute,
-        postprocess=ignore_case if not case_sensitive else None
+        environment, attribute, postprocess=ignore_case if not case_sensitive else None
     )
     return sorted(value, key=key_func, reverse=reverse)
 
@@ -363,8 +370,7 @@ def do_unique(environment, value, case_sensitive=False, attribute=None):
     :param attribute: Filter objects with unique values for this attribute.
     """
     getter = make_attrgetter(
-        environment, attribute,
-        postprocess=ignore_case if not case_sensitive else None
+        environment, attribute, postprocess=ignore_case if not case_sensitive else None
     )
     seen = set()
 
@@ -382,12 +388,10 @@ def _min_or_max(environment, value, func, case_sensitive, attribute):
     try:
         first = next(it)
     except StopIteration:
-        return environment.undefined('No aggregated item, sequence was empty.')
+        return environment.undefined("No aggregated item, sequence was empty.")
 
     key_func = make_attrgetter(
-        environment,
-        attribute,
-        postprocess=ignore_case if not case_sensitive else None
+        environment, attribute, postprocess=ignore_case if not case_sensitive else None
     )
     return func(chain([first], it), key=key_func)
 
@@ -422,7 +426,7 @@ def do_max(environment, value, case_sensitive=False, attribute=None):
     return _min_or_max(environment, value, max, case_sensitive, attribute)
 
 
-def do_default(value, default_value=u'', boolean=False):
+def do_default(value, default_value=u"", boolean=False):
     """If the value is undefined it will return the passed default value,
     otherwise the value of the variable:
 
@@ -451,7 +455,7 @@ def do_default(value, default_value=u'', boolean=False):
 
 
 @evalcontextfilter
-def do_join(eval_ctx, value, d=u'', attribute=None):
+def do_join(eval_ctx, value, d=u"", attribute=None):
     """Return a string which is the concatenation of the strings in the
     sequence. The separator between elements is an empty string per
     default, you can define it with the optional parameter:
@@ -482,11 +486,11 @@ def do_join(eval_ctx, value, d=u'', attribute=None):
 
     # if the delimiter doesn't have an html representation we check
     # if any of the items has.  If yes we do a coercion to Markup
-    if not hasattr(d, '__html__'):
+    if not hasattr(d, "__html__"):
         value = list(value)
         do_escape = False
         for idx, item in enumerate(value):
-            if hasattr(item, '__html__'):
+            if hasattr(item, "__html__"):
                 do_escape = True
             else:
                 value[idx] = text_type(item)
@@ -511,7 +515,7 @@ def do_first(environment, seq):
     try:
         return next(iter(seq))
     except StopIteration:
-        return environment.undefined('No first item, sequence was empty.')
+        return environment.undefined("No first item, sequence was empty.")
 
 
 @environmentfilter
@@ -528,7 +532,7 @@ def do_last(environment, seq):
     try:
         return next(iter(reversed(seq)))
     except StopIteration:
-        return environment.undefined('No last item, sequence was empty.')
+        return environment.undefined("No last item, sequence was empty.")
 
 
 @contextfilter
@@ -537,7 +541,7 @@ def do_random(context, seq):
     try:
         return random.choice(seq)
     except IndexError:
-        return context.environment.undefined('No random item, sequence was empty.')
+        return context.environment.undefined("No random item, sequence was empty.")
 
 
 def do_filesizeformat(value, binary=False):
@@ -549,25 +553,25 @@ def do_filesizeformat(value, binary=False):
     bytes = float(value)
     base = binary and 1024 or 1000
     prefixes = [
-        (binary and 'KiB' or 'kB'),
-        (binary and 'MiB' or 'MB'),
-        (binary and 'GiB' or 'GB'),
-        (binary and 'TiB' or 'TB'),
-        (binary and 'PiB' or 'PB'),
-        (binary and 'EiB' or 'EB'),
-        (binary and 'ZiB' or 'ZB'),
-        (binary and 'YiB' or 'YB')
+        (binary and "KiB" or "kB"),
+        (binary and "MiB" or "MB"),
+        (binary and "GiB" or "GB"),
+        (binary and "TiB" or "TB"),
+        (binary and "PiB" or "PB"),
+        (binary and "EiB" or "EB"),
+        (binary and "ZiB" or "ZB"),
+        (binary and "YiB" or "YB"),
     ]
     if bytes == 1:
-        return '1 Byte'
+        return "1 Byte"
     elif bytes < base:
-        return '%d Bytes' % bytes
+        return "%d Bytes" % bytes
     else:
         for i, prefix in enumerate(prefixes):
             unit = base ** (i + 2)
             if bytes < unit:
-                return '%.1f %s' % ((base * bytes / unit), prefix)
-        return '%.1f %s' % ((base * bytes / unit), prefix)
+                return "%.1f %s" % ((base * bytes / unit), prefix)
+        return "%.1f %s" % ((base * bytes / unit), prefix)
 
 
 def do_pprint(value, verbose=False):
@@ -580,8 +584,9 @@ def do_pprint(value, verbose=False):
 
 
 @evalcontextfilter
-def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False,
-              target=None, rel=None):
+def do_urlize(
+    eval_ctx, value, trim_url_limit=None, nofollow=False, 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
@@ -604,22 +609,20 @@ def do_urlize(eval_ctx, value, trim_url_limit=None, nofollow=False,
        The *target* parameter was added.
     """
     policies = eval_ctx.environment.policies
-    rel = set((rel or '').split() or [])
+    rel = set((rel or "").split() or [])
     if nofollow:
-        rel.add('nofollow')
-    rel.update((policies['urlize.rel'] or '').split())
+        rel.add("nofollow")
+    rel.update((policies["urlize.rel"] or "").split())
     if target is None:
-        target = policies['urlize.target']
-    rel = ' '.join(sorted(rel)) or 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
 
 
-def do_indent(
-    s, width=4, first=False, blank=False, indentfirst=None
-):
+def do_indent(s, width=4, first=False, blank=False, indentfirst=None):
     """Return a copy of the string with each line indented by 4 spaces. The
     first line and blank lines are not indented by default.
 
@@ -633,13 +636,14 @@ def do_indent(
         Rename the ``indentfirst`` argument to ``first``.
     """
     if indentfirst is not None:
-        warnings.warn(DeprecationWarning(
-            'The "indentfirst" argument is renamed to "first".'
-        ), stacklevel=2)
+        warnings.warn(
+            DeprecationWarning('The "indentfirst" argument is renamed to "first".'),
+            stacklevel=2,
+        )
         first = indentfirst
 
-    indention = u' ' * width
-    newline = u'\n'
+    indention = u" " * width
+    newline = u"\n"
 
     if isinstance(s, Markup):
         indention = Markup(indention)
@@ -665,7 +669,7 @@ def do_indent(
 
 
 @environmentfilter
-def do_truncate(env, s, length=255, killwords=False, end='...', leeway=None):
+def do_truncate(env, s, length=255, killwords=False, end="...", leeway=None):
     """Return a truncated copy of the string. The length is specified
     with the first parameter which defaults to ``255``. If the second
     parameter is ``true`` the filter will cut the text at length. Otherwise
@@ -690,14 +694,14 @@ def do_truncate(env, s, length=255, killwords=False, end='...', leeway=None):
     can be reconfigured globally.
     """
     if leeway is None:
-        leeway = env.policies['truncate.leeway']
-    assert length >= len(end), 'expected length >= %s, got %s' % (len(end), length)
-    assert leeway >= 0, 'expected leeway >= 0, got %s' % leeway
+        leeway = env.policies["truncate.leeway"]
+    assert length >= len(end), "expected length >= %s, got %s" % (len(end), length)
+    assert leeway >= 0, "expected leeway >= 0, got %s" % leeway
     if len(s) <= length + leeway:
         return s
     if killwords:
-        return s[:length - len(end)] + end
-    result = s[:length - len(end)].rsplit(' ', 1)[0]
+        return s[: length - len(end)] + end
+    result = s[: length - len(end)].rsplit(" ", 1)[0]
     return result + end
 
 
@@ -816,8 +820,9 @@ def do_format(value, *args, **kwargs):
         #printf-style-string-formatting
     """
     if args and kwargs:
-        raise FilterArgumentError('can\'t handle positional and keyword '
-                                  'arguments at the same time')
+        raise FilterArgumentError(
+            "can't handle positional and keyword arguments at the same time"
+        )
     return soft_unicode(value) % (kwargs or args)
 
 
@@ -827,9 +832,8 @@ def do_trim(value, chars=None):
 
 
 def do_striptags(value):
-    """Strip SGML/XML tags and replace adjacent whitespace by one space.
-    """
-    if hasattr(value, '__html__'):
+    """Strip SGML/XML tags and replace adjacent whitespace by one space."""
+    if hasattr(value, "__html__"):
         value = value.__html__()
     return Markup(text_type(value)).striptags()
 
@@ -901,7 +905,7 @@ def do_batch(value, linecount, fill_with=None):
         yield tmp
 
 
-def do_round(value, precision=0, method='common'):
+def do_round(value, precision=0, method="common"):
     """Round the number to a given precision. The first
     parameter specifies the precision (default is ``0``), the
     second the rounding method:
@@ -927,9 +931,9 @@ def do_round(value, precision=0, method='common'):
         {{ 42.55|round|int }}
             -> 43
     """
-    if not method in ('common', 'ceil', 'floor'):
-        raise FilterArgumentError('method must be common, ceil or floor')
-    if method == 'common':
+    if not method in ("common", "ceil", "floor"):
+        raise FilterArgumentError("method must be common, ceil or floor")
+    if method == "common":
         return round(value, precision)
     func = getattr(math, method)
     return func(value * (10 ** precision)) / (10 ** precision)
@@ -940,7 +944,7 @@ def do_round(value, precision=0, method='common'):
 # we do not want to accidentally expose an auto generated repr in case
 # people start to print this out in comments or something similar for
 # debugging.
-_GroupTuple = namedtuple('_GroupTuple', ['grouper', 'list'])
+_GroupTuple = namedtuple("_GroupTuple", ["grouper", "list"])
 _GroupTuple.__repr__ = tuple.__repr__
 _GroupTuple.__str__ = tuple.__str__
 
@@ -981,8 +985,10 @@ def do_groupby(environment, value, attribute):
         The attribute supports dot notation for nested access.
     """
     expr = make_attrgetter(environment, attribute)
-    return [_GroupTuple(key, list(values)) for key, values
-            in groupby(sorted(value, key=expr), expr)]
+    return [
+        _GroupTuple(key, list(values))
+        for key, values in groupby(sorted(value, key=expr), expr)
+    ]
 
 
 @environmentfilter
@@ -1039,7 +1045,7 @@ def do_reverse(value):
             rv.reverse()
             return rv
         except TypeError:
-            raise FilterArgumentError('argument must be iterable')
+            raise FilterArgumentError("argument must be iterable")
 
 
 @environmentfilter
@@ -1060,8 +1066,9 @@ def do_attr(environment, obj, name):
         except AttributeError:
             pass
         else:
-            if environment.sandboxed and not \
-               environment.is_safe_attribute(obj, name, value):
+            if environment.sandboxed and not environment.is_safe_attribute(
+                obj, name, value
+            ):
                 return environment.unsafe_undefined(obj, name)
             return value
     return environment.undefined(obj=obj, name=name)
@@ -1248,11 +1255,11 @@ def do_tojson(eval_ctx, value, indent=None):
     .. versionadded:: 2.9
     """
     policies = eval_ctx.environment.policies
-    dumper = policies['json.dumps_function']
-    options = policies['json.dumps_kwargs']
+    dumper = policies["json.dumps_function"]
+    options = policies["json.dumps_kwargs"]
     if indent is not None:
         options = dict(options)
-        options['indent'] = indent
+        options["indent"] = indent
     return htmlsafe_json_dumps(value, dumper=dumper, **options)
 
 
@@ -1261,21 +1268,23 @@ def prepare_map(args, kwargs):
     seq = args[1]
     default = None
 
-    if len(args) == 2 and 'attribute' in kwargs:
-        attribute = kwargs.pop('attribute')
-        default = kwargs.pop('default', None)
+    if len(args) == 2 and "attribute" in kwargs:
+        attribute = kwargs.pop("attribute")
+        default = kwargs.pop("default", None)
         if kwargs:
-            raise FilterArgumentError('Unexpected keyword argument %r' %
-                next(iter(kwargs)))
+            raise FilterArgumentError(
+                "Unexpected keyword argument %r" % next(iter(kwargs))
+            )
         func = make_attrgetter(context.environment, attribute, default=default)
     else:
         try:
             name = args[2]
             args = args[3:]
         except LookupError:
-            raise FilterArgumentError('map requires a filter argument')
+            raise FilterArgumentError("map requires a filter argument")
         func = lambda item: context.environment.call_filter(
-            name, item, args, kwargs, context=context)
+            name, item, args, kwargs, context=context
+        )
 
     return seq, func
 
@@ -1287,7 +1296,7 @@ def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr):
         try:
             attr = args[2]
         except LookupError:
-            raise FilterArgumentError('Missing parameter for attribute name')
+            raise FilterArgumentError("Missing parameter for attribute name")
         transfunc = make_attrgetter(context.environment, attr)
         off = 1
     else:
@@ -1296,9 +1305,8 @@ def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr):
 
     try:
         name = args[2 + off]
-        args = args[3 + off:]
-        func = lambda item: context.environment.call_test(
-            name, item, args, kwargs)
+        args = args[3 + off :]
+        func = lambda item: context.environment.call_test(name, item, args, kwargs)
     except LookupError:
         func = bool
 
@@ -1314,57 +1322,57 @@ def select_or_reject(args, kwargs, modfunc, lookup_attr):
 
 
 FILTERS = {
-    'abs':                  abs,
-    'attr':                 do_attr,
-    'batch':                do_batch,
-    'capitalize':           do_capitalize,
-    'center':               do_center,
-    'count':                len,
-    'd':                    do_default,
-    'default':              do_default,
-    'dictsort':             do_dictsort,
-    'e':                    escape,
-    'escape':               escape,
-    'filesizeformat':       do_filesizeformat,
-    'first':                do_first,
-    'float':                do_float,
-    'forceescape':          do_forceescape,
-    'format':               do_format,
-    'groupby':              do_groupby,
-    'indent':               do_indent,
-    'int':                  do_int,
-    'join':                 do_join,
-    'last':                 do_last,
-    'length':               len,
-    'list':                 do_list,
-    'lower':                do_lower,
-    'map':                  do_map,
-    'min':                  do_min,
-    'max':                  do_max,
-    'pprint':               do_pprint,
-    'random':               do_random,
-    'reject':               do_reject,
-    'rejectattr':           do_rejectattr,
-    'replace':              do_replace,
-    'reverse':              do_reverse,
-    'round':                do_round,
-    'safe':                 do_mark_safe,
-    'select':               do_select,
-    'selectattr':           do_selectattr,
-    'slice':                do_slice,
-    'sort':                 do_sort,
-    'string':               soft_unicode,
-    'striptags':            do_striptags,
-    'sum':                  do_sum,
-    'title':                do_title,
-    'trim':                 do_trim,
-    'truncate':             do_truncate,
-    'unique':               do_unique,
-    'upper':                do_upper,
-    'urlencode':            do_urlencode,
-    'urlize':               do_urlize,
-    'wordcount':            do_wordcount,
-    'wordwrap':             do_wordwrap,
-    'xmlattr':              do_xmlattr,
-    'tojson':               do_tojson,
+    "abs": abs,
+    "attr": do_attr,
+    "batch": do_batch,
+    "capitalize": do_capitalize,
+    "center": do_center,
+    "count": len,
+    "d": do_default,
+    "default": do_default,
+    "dictsort": do_dictsort,
+    "e": escape,
+    "escape": escape,
+    "filesizeformat": do_filesizeformat,
+    "first": do_first,
+    "float": do_float,
+    "forceescape": do_forceescape,
+    "format": do_format,
+    "groupby": do_groupby,
+    "indent": do_indent,
+    "int": do_int,
+    "join": do_join,
+    "last": do_last,
+    "length": len,
+    "list": do_list,
+    "lower": do_lower,
+    "map": do_map,
+    "min": do_min,
+    "max": do_max,
+    "pprint": do_pprint,
+    "random": do_random,
+    "reject": do_reject,
+    "rejectattr": do_rejectattr,
+    "replace": do_replace,
+    "reverse": do_reverse,
+    "round": do_round,
+    "safe": do_mark_safe,
+    "select": do_select,
+    "selectattr": do_selectattr,
+    "slice": do_slice,
+    "sort": do_sort,
+    "string": soft_unicode,
+    "striptags": do_striptags,
+    "sum": do_sum,
+    "title": do_title,
+    "trim": do_trim,
+    "truncate": do_truncate,
+    "unique": do_unique,
+    "upper": do_upper,
+    "urlencode": do_urlencode,
+    "urlize": do_urlize,
+    "wordcount": do_wordcount,
+    "wordwrap": do_wordwrap,
+    "xmlattr": do_xmlattr,
+    "tojson": do_tojson,
 }
index 069844c29bb22c9386f449827d1a6d60ca7e64dd..9a0d838017c938fa7a2c4279c4e8edc125608aaf 100644 (file)
@@ -1,10 +1,10 @@
 from ._compat import iteritems
 from .visitor import NodeVisitor
 
-VAR_LOAD_PARAMETER = 'param'
-VAR_LOAD_RESOLVE = 'resolve'
-VAR_LOAD_ALIAS = 'alias'
-VAR_LOAD_UNDEFINED = 'undefined'
+VAR_LOAD_PARAMETER = "param"
+VAR_LOAD_RESOLVE = "resolve"
+VAR_LOAD_ALIAS = "alias"
+VAR_LOAD_UNDEFINED = "undefined"
 
 
 def find_symbols(nodes, parent_symbols=None):
@@ -22,7 +22,6 @@ def symbols_for_node(node, parent_symbols=None):
 
 
 class Symbols(object):
-
     def __init__(self, parent=None, level=None):
         if level is None:
             if parent is None:
@@ -40,7 +39,7 @@ class Symbols(object):
         visitor.visit(node, **kwargs)
 
     def _define_ref(self, name, load=None):
-        ident = 'l_%d_%s' % (self.level, name)
+        ident = "l_%d_%s" % (self.level, name)
         self.refs[name] = ident
         if load is not None:
             self.loads[ident] = load
@@ -61,8 +60,10 @@ class Symbols(object):
     def ref(self, name):
         rv = self.find_ref(name)
         if rv is None:
-            raise AssertionError('Tried to resolve a name to a reference that '
-                                 'was unknown to the frame (%r)' % name)
+            raise AssertionError(
+                "Tried to resolve a name to a reference that "
+                "was unknown to the frame (%r)" % name
+            )
         return rv
 
     def copy(self):
@@ -117,7 +118,7 @@ class Symbols(object):
             if branch_count == len(branch_symbols):
                 continue
             target = self.find_ref(name)
-            assert target is not None, 'should not happen'
+            assert target is not None, "should not happen"
 
             if self.parent is not None:
                 outer_target = self.parent.find_ref(name)
@@ -148,7 +149,6 @@ class Symbols(object):
 
 
 class RootVisitor(NodeVisitor):
-
     def __init__(self, symbols):
         self.sym_visitor = FrameSymbolVisitor(symbols)
 
@@ -156,35 +156,39 @@ class RootVisitor(NodeVisitor):
         for child in node.iter_child_nodes():
             self.sym_visitor.visit(child)
 
-    visit_Template = visit_Block = visit_Macro = visit_FilterBlock = \
-        visit_Scope = visit_If = visit_ScopedEvalContextModifier = \
-        _simple_visit
+    visit_Template = (
+        visit_Block
+    ) = (
+        visit_Macro
+    ) = (
+        visit_FilterBlock
+    ) = visit_Scope = visit_If = visit_ScopedEvalContextModifier = _simple_visit
 
     def visit_AssignBlock(self, node, **kwargs):
         for child in node.body:
             self.sym_visitor.visit(child)
 
     def visit_CallBlock(self, node, **kwargs):
-        for child in node.iter_child_nodes(exclude=('call',)):
+        for child in node.iter_child_nodes(exclude=("call",)):
             self.sym_visitor.visit(child)
 
     def visit_OverlayScope(self, node, **kwargs):
         for child in node.body:
             self.sym_visitor.visit(child)
 
-    def visit_For(self, node, for_branch='body', **kwargs):
-        if for_branch == 'body':
+    def visit_For(self, node, for_branch="body", **kwargs):
+        if for_branch == "body":
             self.sym_visitor.visit(node.target, store_as_param=True)
             branch = node.body
-        elif for_branch == 'else':
+        elif for_branch == "else":
             branch = node.else_
-        elif for_branch == 'test':
+        elif for_branch == "test":
             self.sym_visitor.visit(node.target, store_as_param=True)
             if node.test is not None:
                 self.sym_visitor.visit(node.test)
             return
         else:
-            raise RuntimeError('Unknown for branch')
+            raise RuntimeError("Unknown for branch")
         for item in branch or ():
             self.sym_visitor.visit(item)
 
@@ -195,8 +199,9 @@ class RootVisitor(NodeVisitor):
             self.sym_visitor.visit(child)
 
     def generic_visit(self, node, *args, **kwargs):
-        raise NotImplementedError('Cannot find symbols for %r' %
-                                  node.__class__.__name__)
+        raise NotImplementedError(
+            "Cannot find symbols for %r" % node.__class__.__name__
+        )
 
 
 class FrameSymbolVisitor(NodeVisitor):
@@ -207,11 +212,11 @@ class FrameSymbolVisitor(NodeVisitor):
 
     def visit_Name(self, node, store_as_param=False, **kwargs):
         """All assignments to names go through this function."""
-        if store_as_param or node.ctx == 'param':
+        if store_as_param or node.ctx == "param":
             self.symbols.declare_parameter(node.name)
-        elif node.ctx == 'store':
+        elif node.ctx == "store":
             self.symbols.store(node.name)
-        elif node.ctx == 'load':
+        elif node.ctx == "load":
             self.symbols.load(node.name)
 
     def visit_NSRef(self, node, **kwargs):
index cdd842788d1fde87ac07a943b993a08a0edc561d..1bac2d6b5b352580d1ff4f47732d12a4a83191af 100644 (file)
@@ -31,11 +31,12 @@ from .utils import LRUCache
 _lexer_cache = LRUCache(50)
 
 # static regular expressions
-whitespace_re = re.compile(r'\s+', re.U)
-newline_re = re.compile(r'(\r\n|\r|\n)')
-string_re = re.compile(r"('([^'\\]*(?:\\.[^'\\]*)*)'"
-                       r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S)
-integer_re = re.compile(r'(\d+_)*\d+')
+whitespace_re = re.compile(r"\s+", re.U)
+newline_re = re.compile(r"(\r\n|\r|\n)")
+string_re = re.compile(
+    r"('([^'\\]*(?:\\.[^'\\]*)*)'" r'|"([^"\\]*(?:\\.[^"\\]*)*)")', re.S
+)
+integer_re = re.compile(r"(\d+_)*\d+")
 float_re = re.compile(
     r"""
     (?<!\.)  # doesn't start with a .
@@ -52,134 +53,146 @@ float_re = re.compile(
 
 try:
     # check if this Python supports Unicode identifiers
-    compile('föö', '<unknown>', 'eval')
+    compile("föö", "<unknown>", "eval")
 except SyntaxError:
     # no Unicode support, use ASCII identifiers
-    name_re = re.compile(r'[a-zA-Z_][a-zA-Z0-9_]*')
+    name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
     check_ident = False
 else:
     # Unicode support, build a pattern to match valid characters, and set flag
     # to use str.isidentifier to validate during lexing
     from jinja2 import _identifier
-    name_re = re.compile(r'[\w{0}]+'.format(_identifier.pattern))
+
+    name_re = re.compile(r"[\w{0}]+".format(_identifier.pattern))
     check_ident = True
     # remove the pattern from memory after building the regex
     import sys
-    del sys.modules['jinja2._identifier']
+
+    del sys.modules["jinja2._identifier"]
     import jinja2
+
     del jinja2._identifier
     del _identifier
 
 # internal the tokens and keep references to them
-TOKEN_ADD = intern('add')
-TOKEN_ASSIGN = intern('assign')
-TOKEN_COLON = intern('colon')
-TOKEN_COMMA = intern('comma')
-TOKEN_DIV = intern('div')
-TOKEN_DOT = intern('dot')
-TOKEN_EQ = intern('eq')
-TOKEN_FLOORDIV = intern('floordiv')
-TOKEN_GT = intern('gt')
-TOKEN_GTEQ = intern('gteq')
-TOKEN_LBRACE = intern('lbrace')
-TOKEN_LBRACKET = intern('lbracket')
-TOKEN_LPAREN = intern('lparen')
-TOKEN_LT = intern('lt')
-TOKEN_LTEQ = intern('lteq')
-TOKEN_MOD = intern('mod')
-TOKEN_MUL = intern('mul')
-TOKEN_NE = intern('ne')
-TOKEN_PIPE = intern('pipe')
-TOKEN_POW = intern('pow')
-TOKEN_RBRACE = intern('rbrace')
-TOKEN_RBRACKET = intern('rbracket')
-TOKEN_RPAREN = intern('rparen')
-TOKEN_SEMICOLON = intern('semicolon')
-TOKEN_SUB = intern('sub')
-TOKEN_TILDE = intern('tilde')
-TOKEN_WHITESPACE = intern('whitespace')
-TOKEN_FLOAT = intern('float')
-TOKEN_INTEGER = intern('integer')
-TOKEN_NAME = intern('name')
-TOKEN_STRING = intern('string')
-TOKEN_OPERATOR = intern('operator')
-TOKEN_BLOCK_BEGIN = intern('block_begin')
-TOKEN_BLOCK_END = intern('block_end')
-TOKEN_VARIABLE_BEGIN = intern('variable_begin')
-TOKEN_VARIABLE_END = intern('variable_end')
-TOKEN_RAW_BEGIN = intern('raw_begin')
-TOKEN_RAW_END = intern('raw_end')
-TOKEN_COMMENT_BEGIN = intern('comment_begin')
-TOKEN_COMMENT_END = intern('comment_end')
-TOKEN_COMMENT = intern('comment')
-TOKEN_LINESTATEMENT_BEGIN = intern('linestatement_begin')
-TOKEN_LINESTATEMENT_END = intern('linestatement_end')
-TOKEN_LINECOMMENT_BEGIN = intern('linecomment_begin')
-TOKEN_LINECOMMENT_END = intern('linecomment_end')
-TOKEN_LINECOMMENT = intern('linecomment')
-TOKEN_DATA = intern('data')
-TOKEN_INITIAL = intern('initial')
-TOKEN_EOF = intern('eof')
+TOKEN_ADD = intern("add")
+TOKEN_ASSIGN = intern("assign")
+TOKEN_COLON = intern("colon")
+TOKEN_COMMA = intern("comma")
+TOKEN_DIV = intern("div")
+TOKEN_DOT = intern("dot")
+TOKEN_EQ = intern("eq")
+TOKEN_FLOORDIV = intern("floordiv")
+TOKEN_GT = intern("gt")
+TOKEN_GTEQ = intern("gteq")
+TOKEN_LBRACE = intern("lbrace")
+TOKEN_LBRACKET = intern("lbracket")
+TOKEN_LPAREN = intern("lparen")
+TOKEN_LT = intern("lt")
+TOKEN_LTEQ = intern("lteq")
+TOKEN_MOD = intern("mod")
+TOKEN_MUL = intern("mul")
+TOKEN_NE = intern("ne")
+TOKEN_PIPE = intern("pipe")
+TOKEN_POW = intern("pow")
+TOKEN_RBRACE = intern("rbrace")
+TOKEN_RBRACKET = intern("rbracket")
+TOKEN_RPAREN = intern("rparen")
+TOKEN_SEMICOLON = intern("semicolon")
+TOKEN_SUB = intern("sub")
+TOKEN_TILDE = intern("tilde")
+TOKEN_WHITESPACE = intern("whitespace")
+TOKEN_FLOAT = intern("float")
+TOKEN_INTEGER = intern("integer")
+TOKEN_NAME = intern("name")
+TOKEN_STRING = intern("string")
+TOKEN_OPERATOR = intern("operator")
+TOKEN_BLOCK_BEGIN = intern("block_begin")
+TOKEN_BLOCK_END = intern("block_end")
+TOKEN_VARIABLE_BEGIN = intern("variable_begin")
+TOKEN_VARIABLE_END = intern("variable_end")
+TOKEN_RAW_BEGIN = intern("raw_begin")
+TOKEN_RAW_END = intern("raw_end")
+TOKEN_COMMENT_BEGIN = intern("comment_begin")
+TOKEN_COMMENT_END = intern("comment_end")
+TOKEN_COMMENT = intern("comment")
+TOKEN_LINESTATEMENT_BEGIN = intern("linestatement_begin")
+TOKEN_LINESTATEMENT_END = intern("linestatement_end")
+TOKEN_LINECOMMENT_BEGIN = intern("linecomment_begin")
+TOKEN_LINECOMMENT_END = intern("linecomment_end")
+TOKEN_LINECOMMENT = intern("linecomment")
+TOKEN_DATA = intern("data")
+TOKEN_INITIAL = intern("initial")
+TOKEN_EOF = intern("eof")
 
 # bind operators to token types
 operators = {
-    '+':            TOKEN_ADD,
-    '-':            TOKEN_SUB,
-    '/':            TOKEN_DIV,
-    '//':           TOKEN_FLOORDIV,
-    '*':            TOKEN_MUL,
-    '%':            TOKEN_MOD,
-    '**':           TOKEN_POW,
-    '~':            TOKEN_TILDE,
-    '[':            TOKEN_LBRACKET,
-    ']':            TOKEN_RBRACKET,
-    '(':            TOKEN_LPAREN,
-    ')':            TOKEN_RPAREN,
-    '{':            TOKEN_LBRACE,
-    '}':            TOKEN_RBRACE,
-    '==':           TOKEN_EQ,
-    '!=':           TOKEN_NE,
-    '>':            TOKEN_GT,
-    '>=':           TOKEN_GTEQ,
-    '<':            TOKEN_LT,
-    '<=':           TOKEN_LTEQ,
-    '=':            TOKEN_ASSIGN,
-    '.':            TOKEN_DOT,
-    ':':            TOKEN_COLON,
-    '|':            TOKEN_PIPE,
-    ',':            TOKEN_COMMA,
-    ';':            TOKEN_SEMICOLON
+    "+": TOKEN_ADD,
+    "-": TOKEN_SUB,
+    "/": TOKEN_DIV,
+    "//": TOKEN_FLOORDIV,
+    "*": TOKEN_MUL,
+    "%": TOKEN_MOD,
+    "**": TOKEN_POW,
+    "~": TOKEN_TILDE,
+    "[": TOKEN_LBRACKET,
+    "]": TOKEN_RBRACKET,
+    "(": TOKEN_LPAREN,
+    ")": TOKEN_RPAREN,
+    "{": TOKEN_LBRACE,
+    "}": TOKEN_RBRACE,
+    "==": TOKEN_EQ,
+    "!=": TOKEN_NE,
+    ">": TOKEN_GT,
+    ">=": TOKEN_GTEQ,
+    "<": TOKEN_LT,
+    "<=": TOKEN_LTEQ,
+    "=": TOKEN_ASSIGN,
+    ".": TOKEN_DOT,
+    ":": TOKEN_COLON,
+    "|": TOKEN_PIPE,
+    ",": TOKEN_COMMA,
+    ";": TOKEN_SEMICOLON,
 }
 
 reverse_operators = dict([(v, k) for k, v in iteritems(operators)])
-assert len(operators) == len(reverse_operators), 'operators dropped'
-operator_re = re.compile('(%s)' % '|'.join(re.escape(x) for x in
-                         sorted(operators, key=lambda x: -len(x))))
+assert len(operators) == len(reverse_operators), "operators dropped"
+operator_re = re.compile(
+    "(%s)" % "|".join(re.escape(x) for x in sorted(operators, key=lambda x: -len(x)))
+)
 
-ignored_tokens = frozenset([TOKEN_COMMENT_BEGIN, TOKEN_COMMENT,
-                            TOKEN_COMMENT_END, TOKEN_WHITESPACE,
-                            TOKEN_LINECOMMENT_BEGIN, TOKEN_LINECOMMENT_END,
-                            TOKEN_LINECOMMENT])
-ignore_if_empty = frozenset([TOKEN_WHITESPACE, TOKEN_DATA,
-                             TOKEN_COMMENT, TOKEN_LINECOMMENT])
+ignored_tokens = frozenset(
+    [
+        TOKEN_COMMENT_BEGIN,
+        TOKEN_COMMENT,
+        TOKEN_COMMENT_END,
+        TOKEN_WHITESPACE,
+        TOKEN_LINECOMMENT_BEGIN,
+        TOKEN_LINECOMMENT_END,
+        TOKEN_LINECOMMENT,
+    ]
+)
+ignore_if_empty = frozenset(
+    [TOKEN_WHITESPACE, TOKEN_DATA, TOKEN_COMMENT, TOKEN_LINECOMMENT]
+)
 
 
 def _describe_token_type(token_type):
     if token_type in reverse_operators:
         return reverse_operators[token_type]
     return {
-        TOKEN_COMMENT_BEGIN:        'begin of comment',
-        TOKEN_COMMENT_END:          'end of comment',
-        TOKEN_COMMENT:              'comment',
-        TOKEN_LINECOMMENT:          'comment',
-        TOKEN_BLOCK_BEGIN:          'begin of statement block',
-        TOKEN_BLOCK_END:            'end of statement block',
-        TOKEN_VARIABLE_BEGIN:       'begin of print statement',
-        TOKEN_VARIABLE_END:         'end of print statement',
-        TOKEN_LINESTATEMENT_BEGIN:  'begin of line statement',
-        TOKEN_LINESTATEMENT_END:    'end of line statement',
-        TOKEN_DATA:                 'template data / text',
-        TOKEN_EOF:                  'end of template'
+        TOKEN_COMMENT_BEGIN: "begin of comment",
+        TOKEN_COMMENT_END: "end of comment",
+        TOKEN_COMMENT: "comment",
+        TOKEN_LINECOMMENT: "comment",
+        TOKEN_BLOCK_BEGIN: "begin of statement block",
+        TOKEN_BLOCK_END: "end of statement block",
+        TOKEN_VARIABLE_BEGIN: "begin of print statement",
+        TOKEN_VARIABLE_END: "end of print statement",
+        TOKEN_LINESTATEMENT_BEGIN: "begin of line statement",
+        TOKEN_LINESTATEMENT_END: "end of line statement",
+        TOKEN_DATA: "template data / text",
+        TOKEN_EOF: "end of template",
     }.get(token_type, token_type)
 
 
@@ -192,8 +205,8 @@ def describe_token(token):
 
 def describe_token_expr(expr):
     """Like `describe_token` but for token expressions."""
-    if ':' in expr:
-        type, value = expr.split(':', 1)
+    if ":" in expr:
+        type, value = expr.split(":", 1)
         if type == TOKEN_NAME:
             return value
     else:
@@ -212,21 +225,39 @@ def compile_rules(environment):
     """Compiles all the rules from the environment into a list of rules."""
     e = re.escape
     rules = [
-        (len(environment.comment_start_string), TOKEN_COMMENT_BEGIN,
-         e(environment.comment_start_string)),
-        (len(environment.block_start_string), TOKEN_BLOCK_BEGIN,
-         e(environment.block_start_string)),
-        (len(environment.variable_start_string), TOKEN_VARIABLE_BEGIN,
-         e(environment.variable_start_string))
+        (
+            len(environment.comment_start_string),
+            TOKEN_COMMENT_BEGIN,
+            e(environment.comment_start_string),
+        ),
+        (
+            len(environment.block_start_string),
+            TOKEN_BLOCK_BEGIN,
+            e(environment.block_start_string),
+        ),
+        (
+            len(environment.variable_start_string),
+            TOKEN_VARIABLE_BEGIN,
+            e(environment.variable_start_string),
+        ),
     ]
 
     if environment.line_statement_prefix is not None:
-        rules.append((len(environment.line_statement_prefix), TOKEN_LINESTATEMENT_BEGIN,
-                      r'^[ \t\v]*' + e(environment.line_statement_prefix)))
+        rules.append(
+            (
+                len(environment.line_statement_prefix),
+                TOKEN_LINESTATEMENT_BEGIN,
+                r"^[ \t\v]*" + e(environment.line_statement_prefix),
+            )
+        )
     if environment.line_comment_prefix is not None:
-        rules.append((len(environment.line_comment_prefix), TOKEN_LINECOMMENT_BEGIN,
-                      r'(?:^|(?<=\S))[^\S\r\n]*' +
-                      e(environment.line_comment_prefix)))
+        rules.append(
+            (
+                len(environment.line_comment_prefix),
+                TOKEN_LINECOMMENT_BEGIN,
+                r"(?:^|(?<=\S))[^\S\r\n]*" + e(environment.line_comment_prefix),
+            )
+        )
 
     return [x[1:] for x in sorted(rules, reverse=True)]
 
@@ -246,6 +277,7 @@ class Failure(object):
 
 class Token(tuple):
     """Token class."""
+
     __slots__ = ()
     lineno, type, value = (property(itemgetter(x)) for x in range(3))
 
@@ -255,7 +287,7 @@ class Token(tuple):
     def __str__(self):
         if self.type in reverse_operators:
             return reverse_operators[self.type]
-        elif self.type == 'name':
+        elif self.type == "name":
             return self.value
         return self.type
 
@@ -268,8 +300,8 @@ class Token(tuple):
         # passed an iterable of not interned strings.
         if self.type == expr:
             return True
-        elif ':' in expr:
-            return expr.split(':', 1) == [self.type, self.value]
+        elif ":" in expr:
+            return expr.split(":", 1) == [self.type, self.value]
         return False
 
     def test_any(self, *iterable):
@@ -280,11 +312,7 @@ class Token(tuple):
         return False
 
     def __repr__(self):
-        return 'Token(%r, %r, %r)' % (
-            self.lineno,
-            self.type,
-            self.value
-        )
+        return "Token(%r, %r, %r)" % (self.lineno, self.type, self.value)
 
 
 @implements_iterator
@@ -321,7 +349,7 @@ class TokenStream(object):
         self.name = name
         self.filename = filename
         self.closed = False
-        self.current = Token(1, TOKEN_INITIAL, '')
+        self.current = Token(1, TOKEN_INITIAL, "")
         next(self)
 
     def __iter__(self):
@@ -329,6 +357,7 @@ class TokenStream(object):
 
     def __bool__(self):
         return bool(self._pushed) or self.current.type is not TOKEN_EOF
+
     __nonzero__ = __bool__  # py2
 
     @property
@@ -381,7 +410,7 @@ class TokenStream(object):
 
     def close(self):
         """Close the stream."""
-        self.current = Token(self.current.lineno, TOKEN_EOF, '')
+        self.current = Token(self.current.lineno, TOKEN_EOF, "")
         self._iter = None
         self.closed = True
 
@@ -392,14 +421,18 @@ class TokenStream(object):
         if not self.current.test(expr):
             expr = describe_token_expr(expr)
             if self.current.type is TOKEN_EOF:
-                raise TemplateSyntaxError('unexpected end of template, '
-                                          'expected %r.' % expr,
-                                          self.current.lineno,
-                                          self.name, self.filename)
-            raise TemplateSyntaxError("expected token %r, got %r" %
-                                      (expr, describe_token(self.current)),
-                                      self.current.lineno,
-                                      self.name, self.filename)
+                raise TemplateSyntaxError(
+                    "unexpected end of template, expected %r." % expr,
+                    self.current.lineno,
+                    self.name,
+                    self.filename,
+                )
+            raise TemplateSyntaxError(
+                "expected token %r, got %r" % (expr, describe_token(self.current)),
+                self.current.lineno,
+                self.name,
+                self.filename,
+            )
         try:
             return self.current
         finally:
@@ -408,18 +441,20 @@ class TokenStream(object):
 
 def get_lexer(environment):
     """Return a lexer which is probably cached."""
-    key = (environment.block_start_string,
-           environment.block_end_string,
-           environment.variable_start_string,
-           environment.variable_end_string,
-           environment.comment_start_string,
-           environment.comment_end_string,
-           environment.line_statement_prefix,
-           environment.line_comment_prefix,
-           environment.trim_blocks,
-           environment.lstrip_blocks,
-           environment.newline_sequence,
-           environment.keep_trailing_newline)
+    key = (
+        environment.block_start_string,
+        environment.block_end_string,
+        environment.variable_start_string,
+        environment.variable_end_string,
+        environment.comment_start_string,
+        environment.comment_end_string,
+        environment.line_statement_prefix,
+        environment.line_comment_prefix,
+        environment.trim_blocks,
+        environment.lstrip_blocks,
+        environment.newline_sequence,
+        environment.keep_trailing_newline,
+    )
     lexer = _lexer_cache.get(key)
     if lexer is None:
         lexer = Lexer(environment)
@@ -460,7 +495,7 @@ class Lexer(object):
             (integer_re, TOKEN_INTEGER, None),
             (name_re, TOKEN_NAME, None),
             (string_re, TOKEN_STRING, None),
-            (operator_re, TOKEN_OPERATOR, None)
+            (operator_re, TOKEN_OPERATOR, None),
         ]
 
         # assemble the root lexing rule. because "|" is ungreedy
@@ -472,7 +507,7 @@ class Lexer(object):
         root_tag_rules = compile_rules(environment)
 
         # block suffix if trimming is enabled
-        block_suffix_re = environment.trim_blocks and '\\n?' or ''
+        block_suffix_re = environment.trim_blocks and "\\n?" or ""
 
         # If lstrip is enabled, it should not be applied if there is any
         # non-whitespace between the newline and block.
@@ -483,63 +518,109 @@ class Lexer(object):
 
         # global lexing rules
         self.rules = {
-            'root': [
+            "root": [
                 # directives
-                (c('(.*?)(?:%s)' % '|'.join(
-                    [r'(?P<raw_begin>%s(\-|\+|)\s*raw\s*(?:\-%s\s*|%s))' % (
-                        e(environment.block_start_string),
-                        e(environment.block_end_string),
-                        e(environment.block_end_string)
-                    )] + [
-                        r'(?P<%s>%s(\-|\+|))' % (n, r)
-                        for n, r in root_tag_rules
-                    ])), OptionalLStrip(TOKEN_DATA, '#bygroup'), '#bygroup'),
+                (
+                    c(
+                        "(.*?)(?:%s)"
+                        % "|".join(
+                            [
+                                r"(?P<raw_begin>%s(\-|\+|)\s*raw\s*(?:\-%s\s*|%s))"
+                                % (
+                                    e(environment.block_start_string),
+                                    e(environment.block_end_string),
+                                    e(environment.block_end_string),
+                                )
+                            ]
+                            + [
+                                r"(?P<%s>%s(\-|\+|))" % (n, r)
+                                for n, r in root_tag_rules
+                            ]
+                        )
+                    ),
+                    OptionalLStrip(TOKEN_DATA, "#bygroup"),
+                    "#bygroup",
+                ),
                 # data
-                (c('.+'), TOKEN_DATA, None)
+                (c(".+"), TOKEN_DATA, None),
             ],
             # comments
             TOKEN_COMMENT_BEGIN: [
-                (c(r'(.*?)((?:\-%s\s*|%s)%s)' % (
-                    e(environment.comment_end_string),
-                    e(environment.comment_end_string),
-                    block_suffix_re
-                )), (TOKEN_COMMENT, TOKEN_COMMENT_END), '#pop'),
-                (c('(.)'), (Failure('Missing end of comment tag'),), None)
+                (
+                    c(
+                        r"(.*?)((?:\-%s\s*|%s)%s)"
+                        % (
+                            e(environment.comment_end_string),
+                            e(environment.comment_end_string),
+                            block_suffix_re,
+                        )
+                    ),
+                    (TOKEN_COMMENT, TOKEN_COMMENT_END),
+                    "#pop",
+                ),
+                (c("(.)"), (Failure("Missing end of comment tag"),), None),
             ],
             # blocks
             TOKEN_BLOCK_BEGIN: [
-                (c(r'(?:\-%s\s*|%s)%s' % (
-                    e(environment.block_end_string),
-                    e(environment.block_end_string),
-                    block_suffix_re
-                )), TOKEN_BLOCK_END, '#pop'),
-            ] + tag_rules,
+                (
+                    c(
+                        r"(?:\-%s\s*|%s)%s"
+                        % (
+                            e(environment.block_end_string),
+                            e(environment.block_end_string),
+                            block_suffix_re,
+                        )
+                    ),
+                    TOKEN_BLOCK_END,
+                    "#pop",
+                ),
+            ]
+            + tag_rules,
             # variables
             TOKEN_VARIABLE_BEGIN: [
-                (c(r'\-%s\s*|%s' % (
-                    e(environment.variable_end_string),
-                    e(environment.variable_end_string)
-                )), TOKEN_VARIABLE_END, '#pop')
-            ] + tag_rules,
+                (
+                    c(
+                        r"\-%s\s*|%s"
+                        % (
+                            e(environment.variable_end_string),
+                            e(environment.variable_end_string),
+                        )
+                    ),
+                    TOKEN_VARIABLE_END,
+                    "#pop",
+                )
+            ]
+            + tag_rules,
             # raw block
             TOKEN_RAW_BEGIN: [
-                (c(r'(.*?)((?:%s(\-|\+|))\s*endraw\s*(?:\-%s\s*|%s%s))' % (
-                    e(environment.block_start_string),
-                    e(environment.block_end_string),
-                    e(environment.block_end_string),
-                    block_suffix_re
-                )), OptionalLStrip(TOKEN_DATA, TOKEN_RAW_END), '#pop'),
-                (c('(.)'), (Failure('Missing end of raw directive'),), None)
+                (
+                    c(
+                        r"(.*?)((?:%s(\-|\+|))\s*endraw\s*(?:\-%s\s*|%s%s))"
+                        % (
+                            e(environment.block_start_string),
+                            e(environment.block_end_string),
+                            e(environment.block_end_string),
+                            block_suffix_re,
+                        )
+                    ),
+                    OptionalLStrip(TOKEN_DATA, TOKEN_RAW_END),
+                    "#pop",
+                ),
+                (c("(.)"), (Failure("Missing end of raw directive"),), None),
             ],
             # line statements
             TOKEN_LINESTATEMENT_BEGIN: [
-                (c(r'\s*(\n|$)'), TOKEN_LINESTATEMENT_END, '#pop')
-            ] + tag_rules,
+                (c(r"\s*(\n|$)"), TOKEN_LINESTATEMENT_END, "#pop")
+            ]
+            + tag_rules,
             # line comments
             TOKEN_LINECOMMENT_BEGIN: [
-                (c(r'(.*?)()(?=\n|$)'), (TOKEN_LINECOMMENT,
-                 TOKEN_LINECOMMENT_END), '#pop')
-            ]
+                (
+                    c(r"(.*?)()(?=\n|$)"),
+                    (TOKEN_LINECOMMENT, TOKEN_LINECOMMENT_END),
+                    "#pop",
+                )
+            ],
         }
 
     def _normalize_newlines(self, value):
@@ -547,8 +628,7 @@ class Lexer(object):
         return newline_re.sub(self.newline_sequence, value)
 
     def tokenize(self, source, name=None, filename=None, state=None):
-        """Calls tokeniter + tokenize and wraps it in a token stream.
-        """
+        """Calls tokeniter + tokenize and wraps it in a token stream."""
         stream = self.tokeniter(source, name, filename, state)
         return TokenStream(self.wrap(stream, name, filename), name, filename)
 
@@ -568,22 +648,24 @@ class Lexer(object):
                 continue
             elif token == TOKEN_DATA:
                 value = self._normalize_newlines(value)
-            elif token == 'keyword':
+            elif token == "keyword":
                 token = value
             elif token == TOKEN_NAME:
                 value = str(value)
                 if check_ident and not value.isidentifier():
                     raise TemplateSyntaxError(
-                        'Invalid character in identifier',
-                        lineno, name, filename)
+                        "Invalid character in identifier", lineno, name, filename
+                    )
             elif token == TOKEN_STRING:
                 # try to unescape string
                 try:
-                    value = self._normalize_newlines(value[1:-1]) \
-                        .encode('ascii', 'backslashreplace') \
-                        .decode('unicode-escape')
+                    value = (
+                        self._normalize_newlines(value[1:-1])
+                        .encode("ascii", "backslashreplace")
+                        .decode("unicode-escape")
+                    )
                 except Exception as e:
-                    msg = str(e).split(':')[-1].strip()
+                    msg = str(e).split(":")[-1].strip()
                     raise TemplateSyntaxError(msg, lineno, name, filename)
             elif token == TOKEN_INTEGER:
                 value = int(value.replace("_", ""))
@@ -601,17 +683,17 @@ class Lexer(object):
         source = text_type(source)
         lines = source.splitlines()
         if self.keep_trailing_newline and source:
-            for newline in ('\r\n', '\r', '\n'):
+            for newline in ("\r\n", "\r", "\n"):
                 if source.endswith(newline):
-                    lines.append('')
+                    lines.append("")
                     break
-        source = '\n'.join(lines)
+        source = "\n".join(lines)
         pos = 0
         lineno = 1
-        stack = ['root']
-        if state is not None and state != 'root':
-            assert state in ('variable', 'block'), 'invalid state'
-            stack.append(state + '_begin')
+        stack = ["root"]
+        if state is not None and state != "root":
+            assert state in ("variable", "block"), "invalid state"
+            stack.append(state + "_begin")
         statetokens = self.rules[stack[-1]]
         source_length = len(source)
         balancing_stack = []
@@ -629,11 +711,10 @@ class Lexer(object):
                 # are balanced. continue parsing with the lower rule which
                 # is the operator rule. do this only if the end tags look
                 # like operators
-                if (
-                    balancing_stack
-                    and tokens in (
-                        TOKEN_VARIABLE_END, TOKEN_BLOCK_END, TOKEN_LINESTATEMENT_END
-                    )
+                if balancing_stack and tokens in (
+                    TOKEN_VARIABLE_END,
+                    TOKEN_BLOCK_END,
+                    TOKEN_LINESTATEMENT_END,
                 ):
                     continue
 
@@ -663,7 +744,7 @@ class Lexer(object):
                             and not m.groupdict().get(TOKEN_VARIABLE_BEGIN)
                         ):
                             # The start of text between the last newline and the tag.
-                            l_pos = text.rfind('\n') + 1
+                            l_pos = text.rfind("\n") + 1
 
                             # If there's only whitespace between the newline and the
                             # tag, strip it.
@@ -677,51 +758,54 @@ class Lexer(object):
                         # bygroup is a bit more complex, in that case we
                         # yield for the current token the first named
                         # group that matched
-                        elif token == '#bygroup':
+                        elif token == "#bygroup":
                             for key, value in iteritems(m.groupdict()):
                                 if value is not None:
                                     yield lineno, key, value
-                                    lineno += value.count('\n')
+                                    lineno += value.count("\n")
                                     break
                             else:
-                                raise RuntimeError('%r wanted to resolve '
-                                                   'the token dynamically'
-                                                   ' but no group matched'
-                                                   % regex)
+                                raise RuntimeError(
+                                    "%r wanted to resolve "
+                                    "the token dynamically"
+                                    " but no group matched" % regex
+                                )
                         # normal group
                         else:
                             data = groups[idx]
                             if data or token not in ignore_if_empty:
                                 yield lineno, token, data
-                            lineno += data.count('\n')
+                            lineno += data.count("\n")
 
                 # strings as token just are yielded as it.
                 else:
                     data = m.group()
                     # update brace/parentheses balance
                     if tokens == TOKEN_OPERATOR:
-                        if data == '{':
-                            balancing_stack.append('}')
-                        elif data == '(':
-                            balancing_stack.append(')')
-                        elif data == '[':
-                            balancing_stack.append(']')
-                        elif data in ('}', ')', ']'):
+                        if data == "{":
+                            balancing_stack.append("}")
+                        elif data == "(":
+                            balancing_stack.append(")")
+                        elif data == "[":
+                            balancing_stack.append("]")
+                        elif data in ("}", ")", "]"):
                             if not balancing_stack:
-                                raise TemplateSyntaxError('unexpected \'%s\'' %
-                                                          data, lineno, name,
-                                                          filename)
+                                raise TemplateSyntaxError(
+                                    "unexpected '%s'" % data, lineno, name, filename
+                                )
                             expected_op = balancing_stack.pop()
                             if expected_op != data:
-                                raise TemplateSyntaxError('unexpected \'%s\', '
-                                                          'expected \'%s\'' %
-                                                          (data, expected_op),
-                                                          lineno, name,
-                                                          filename)
+                                raise TemplateSyntaxError(
+                                    "unexpected '%s', "
+                                    "expected '%s'" % (data, expected_op),
+                                    lineno,
+                                    name,
+                                    filename,
+                                )
                     # yield items
                     if data or tokens not in ignore_if_empty:
                         yield lineno, tokens, data
-                    lineno += data.count('\n')
+                    lineno += data.count("\n")
 
                 # fetch new position into new variable so that we can check
                 # if there is a internal parsing error which would result
@@ -731,19 +815,20 @@ class Lexer(object):
                 # handle state changes
                 if new_state is not None:
                     # remove the uppermost state
-                    if new_state == '#pop':
+                    if new_state == "#pop":
                         stack.pop()
                     # resolve the new state by group checking
-                    elif new_state == '#bygroup':
+                    elif new_state == "#bygroup":
                         for key, value in iteritems(m.groupdict()):
                             if value is not None:
                                 stack.append(key)
                                 break
                         else:
-                            raise RuntimeError('%r wanted to resolve the '
-                                               'new state dynamically but'
-                                               ' no group matched' %
-                                               regex)
+                            raise RuntimeError(
+                                "%r wanted to resolve the "
+                                "new state dynamically but"
+                                " no group matched" % regex
+                            )
                     # direct state name given
                     else:
                         stack.append(new_state)
@@ -752,8 +837,9 @@ class Lexer(object):
                 # this means a loop without break condition, avoid that and
                 # raise error
                 elif pos2 == pos:
-                    raise RuntimeError('%r yielded empty string without '
-                                       'stack change' % regex)
+                    raise RuntimeError(
+                        "%r yielded empty string without stack change" % regex
+                    )
                 # publish new function and start again
                 pos = pos2
                 break
@@ -764,6 +850,9 @@ class Lexer(object):
                 if pos >= source_length:
                     return
                 # something went wrong
-                raise TemplateSyntaxError('unexpected char %r at %d' %
-                                          (source[pos], pos), lineno,
-                                          name, filename)
+                raise TemplateSyntaxError(
+                    "unexpected char %r at %d" % (source[pos], pos),
+                    lineno,
+                    name,
+                    filename,
+                )
index 86049f7099cc02a33195aaadf1fe936ff566de66..fa91a735aebb35cbb46455ad9c471dd3073d6c75 100644 (file)
@@ -31,12 +31,14 @@ def split_template_path(template):
     '..' in the path it will raise a `TemplateNotFound` error.
     """
     pieces = []
-    for piece in template.split('/'):
-        if path.sep in piece \
-           or (path.altsep and path.altsep in piece) or \
-           piece == path.pardir:
+    for piece in template.split("/"):
+        if (
+            path.sep in piece
+            or (path.altsep and path.altsep in piece)
+            or piece == path.pardir
+        ):
             raise TemplateNotFound(template)
-        elif piece and piece != '.':
+        elif piece and piece != ".":
             pieces.append(piece)
     return pieces
 
@@ -93,15 +95,16 @@ class BaseLoader(object):
         the template will be reloaded.
         """
         if not self.has_source_access:
-            raise RuntimeError('%s cannot provide access to the source' %
-                               self.__class__.__name__)
+            raise RuntimeError(
+                "%s cannot provide access to the source" % self.__class__.__name__
+            )
         raise TemplateNotFound(template)
 
     def list_templates(self):
         """Iterates over all templates.  If the loader does not support that
         it should raise a :exc:`TypeError` which is the default behavior.
         """
-        raise TypeError('this loader cannot iterate over all templates')
+        raise TypeError("this loader cannot iterate over all templates")
 
     @internalcode
     def load(self, environment, name, globals=None):
@@ -138,8 +141,9 @@ class BaseLoader(object):
             bucket.code = code
             bcc.set_bucket(bucket)
 
-        return environment.template_class.from_code(environment, code,
-                                                    globals, uptodate)
+        return environment.template_class.from_code(
+            environment, code, globals, uptodate
+        )
 
 
 class FileSystemLoader(BaseLoader):
@@ -164,10 +168,9 @@ class FileSystemLoader(BaseLoader):
        The ``followlinks`` parameter was added.
     """
 
-    def __init__(self, searchpath, encoding='utf-8', followlinks=False):
-        if (
-            not isinstance(searchpath, abc.Iterable)
-            or isinstance(searchpath, string_types)
+    def __init__(self, searchpath, encoding="utf-8", followlinks=False):
+        if not isinstance(searchpath, abc.Iterable) or isinstance(
+            searchpath, string_types
         ):
             searchpath = [searchpath]
 
@@ -197,6 +200,7 @@ class FileSystemLoader(BaseLoader):
                     return path.getmtime(filename) == mtime
                 except OSError:
                     return False
+
             return contents, filename, uptodate
         raise TemplateNotFound(template)
 
@@ -206,10 +210,12 @@ class FileSystemLoader(BaseLoader):
             walk_dir = os.walk(searchpath, followlinks=self.followlinks)
             for dirpath, dirnames, filenames in walk_dir:
                 for filename in filenames:
-                    template = os.path.join(dirpath, filename) \
-                        [len(searchpath):].strip(os.path.sep) \
-                                          .replace(os.path.sep, '/')
-                    if template[:2] == './':
+                    template = (
+                        os.path.join(dirpath, filename)[len(searchpath) :]
+                        .strip(os.path.sep)
+                        .replace(os.path.sep, "/")
+                    )
+                    if template[:2] == "./":
                         template = template[2:]
                     if template not in found:
                         found.add(template)
@@ -305,6 +311,7 @@ class PackageLoader(BaseLoader):
 
             def up_to_date():
                 return os.path.isfile(p) and os.path.getmtime(p) == mtime
+
         else:
             # Package is a zip file.
             try:
@@ -341,7 +348,7 @@ class PackageLoader(BaseLoader):
 
             # Package is a zip file.
             prefix = (
-                self._template_root[len(self._archive):].lstrip(os.path.sep)
+                self._template_root[len(self._archive) :].lstrip(os.path.sep)
                 + os.path.sep
             )
             offset = len(prefix)
@@ -422,7 +429,7 @@ class PrefixLoader(BaseLoader):
     by loading ``'app2/index.html'`` the file from the second.
     """
 
-    def __init__(self, mapping, delimiter='/'):
+    def __init__(self, mapping, delimiter="/"):
         self.mapping = mapping
         self.delimiter = delimiter
 
@@ -522,22 +529,20 @@ class ModuleLoader(BaseLoader):
     has_source_access = False
 
     def __init__(self, path):
-        package_name = '_jinja2_module_templates_%x' % id(self)
+        package_name = "_jinja2_module_templates_%x" % id(self)
 
         # create a fake module that looks for the templates in the
         # path given.
         mod = _TemplateModule(package_name)
 
-        if (
-            not isinstance(path, abc.Iterable)
-            or isinstance(path, string_types)
-        ):
+        if not isinstance(path, abc.Iterable) or isinstance(path, string_types):
             path = [path]
 
         mod.__path__ = [fspath(p) for p in path]
 
-        sys.modules[package_name] = weakref.proxy(mod,
-            lambda x: sys.modules.pop(package_name, None))
+        sys.modules[package_name] = weakref.proxy(
+            mod, lambda x: sys.modules.pop(package_name, None)
+        )
 
         # the only strong reference, the sys.modules entry is weak
         # so that the garbage collector can remove it once the
@@ -547,20 +552,20 @@ class ModuleLoader(BaseLoader):
 
     @staticmethod
     def get_template_key(name):
-        return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest()
+        return "tmpl_" + sha1(name.encode("utf-8")).hexdigest()
 
     @staticmethod
     def get_module_filename(name):
-        return ModuleLoader.get_template_key(name) + '.py'
+        return ModuleLoader.get_template_key(name) + ".py"
 
     @internalcode
     def load(self, environment, name, globals=None):
         key = self.get_template_key(name)
-        module = '%s.%s' % (self.package_name, key)
+        module = "%s.%s" % (self.package_name, key)
         mod = getattr(self.module, module, None)
         if mod is None:
             try:
-                mod = __import__(module, None, None, ['root'])
+                mod = __import__(module, None, None, ["root"])
             except ImportError:
                 raise TemplateNotFound(name)
 
@@ -569,4 +574,5 @@ class ModuleLoader(BaseLoader):
             sys.modules.pop(module, None)
 
         return environment.template_class.from_module_dict(
-            environment, mod.__dict__, globals)
+            environment, mod.__dict__, globals
+        )
index 6a4208eec18deafc25513b87ca1fbc4d9a30c5bf..3c7917ef6e7caead0aabf23bd622faca2fc404f9 100644 (file)
@@ -19,8 +19,7 @@ class TrackingCodeGenerator(CodeGenerator):
     """We abuse the code generator for introspection."""
 
     def __init__(self, environment):
-        CodeGenerator.__init__(self, environment, '<introspection>',
-                               '<introspection>')
+        CodeGenerator.__init__(self, environment, "<introspection>", "<introspection>")
         self.undeclared_identifiers = set()
 
     def write(self, x):
@@ -30,7 +29,7 @@ class TrackingCodeGenerator(CodeGenerator):
         """Remember all undeclared identifiers."""
         CodeGenerator.enter_frame(self, frame)
         for _, (action, param) in iteritems(frame.symbols.loads):
-            if action == 'resolve' and param not in self.environment.globals:
+            if action == "resolve" and param not in self.environment.globals:
                 self.undeclared_identifiers.add(param)
 
 
@@ -73,8 +72,9 @@ def find_referenced_templates(ast):
     This function is useful for dependency tracking.  For example if you want
     to rebuild parts of the website after a layout template has changed.
     """
-    for node in ast.find_all((nodes.Extends, nodes.FromImport, nodes.Import,
-                              nodes.Include)):
+    for node in ast.find_all(
+        (nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include)
+    ):
         if not isinstance(node.template, nodes.Const):
             # a tuple with some non consts in there
             if isinstance(node.template, (nodes.Tuple, nodes.List)):
@@ -97,8 +97,9 @@ def find_referenced_templates(ast):
         # a tuple or list (latter *should* not happen) made of consts,
         # yield the consts that are strings.  We could warn here for
         # non string values
-        elif isinstance(node, nodes.Include) and \
-             isinstance(node.template.value, (tuple, list)):
+        elif isinstance(node, nodes.Include) and isinstance(
+            node.template.value, (tuple, list)
+        ):
             for template_name in node.template.value:
                 if isinstance(template_name, string_types):
                     yield template_name
index 6b3e5f536975b8e90c95c3a0c958e5dd4275dd7d..9866c962dcff21bb2dbc47c1a4252ef52f773124 100644 (file)
@@ -33,7 +33,7 @@ def native_concat(nodes, preserve_quotes=True):
     else:
         if isinstance(nodes, types.GeneratorType):
             nodes = chain(head, nodes)
-        raw = u''.join([text_type(v) for v in nodes])
+        raw = u"".join([text_type(v) for v in nodes])
 
     try:
         literal = literal_eval(raw)
index 36d921d40a2ed31c03e2745428e0e10971ef8f19..65b259931971f98023c9350f8651e07b46259068 100644 (file)
@@ -22,30 +22,26 @@ from ._compat import with_metaclass
 from .utils import Markup
 
 _binop_to_func = {
-    '*':        operator.mul,
-    '/':        operator.truediv,
-    '//':       operator.floordiv,
-    '**':       operator.pow,
-    '%':        operator.mod,
-    '+':        operator.add,
-    '-':        operator.sub
+    "*": operator.mul,
+    "/": operator.truediv,
+    "//": operator.floordiv,
+    "**": operator.pow,
+    "%": operator.mod,
+    "+": operator.add,
+    "-": operator.sub,
 }
 
-_uaop_to_func = {
-    'not':      operator.not_,
-    '+':        operator.pos,
-    '-':        operator.neg
-}
+_uaop_to_func = {"not": operator.not_, "+": operator.pos, "-": operator.neg}
 
 _cmpop_to_func = {
-    'eq':       operator.eq,
-    'ne':       operator.ne,
-    'gt':       operator.gt,
-    'gteq':     operator.ge,
-    'lt':       operator.lt,
-    'lteq':     operator.le,
-    'in':       lambda a, b: a in b,
-    'notin':    lambda a, b: a not in b
+    "eq": operator.eq,
+    "ne": operator.ne,
+    "gt": operator.gt,
+    "gteq": operator.ge,
+    "lt": operator.lt,
+    "lteq": operator.le,
+    "in": lambda a, b: a in b,
+    "notin": lambda a, b: a not in b,
 }
 
 
@@ -59,14 +55,14 @@ class NodeType(type):
     automatically forwarded to the child."""
 
     def __new__(cls, name, bases, d):
-        for attr in 'fields', 'attributes':
+        for attr in "fields", "attributes":
             storage = []
             storage.extend(getattr(bases[0], attr, ()))
             storage.extend(d.get(attr, ()))
-            assert len(bases) == 1, 'multiple inheritance not allowed'
-            assert len(storage) == len(set(storage)), 'layout conflict'
+            assert len(bases) == 1, "multiple inheritance not allowed"
+            assert len(storage) == len(set(storage)), "layout conflict"
             d[attr] = tuple(storage)
-        d.setdefault('abstract', False)
+        d.setdefault("abstract", False)
         return type.__new__(cls, name, bases, d)
 
 
@@ -94,9 +90,11 @@ class EvalContext(object):
 def get_eval_context(node, ctx):
     if ctx is None:
         if node.environment is None:
-            raise RuntimeError('if no eval context is passed, the '
-                               'node must have an attached '
-                               'environment.')
+            raise RuntimeError(
+                "if no eval context is passed, the "
+                "node must have an attached "
+                "environment."
+            )
         return EvalContext(node.environment)
     return ctx
 
@@ -117,30 +115,32 @@ class Node(with_metaclass(NodeType, object)):
     The `environment` attribute is set at the end of the parsing process for
     all nodes automatically.
     """
+
     fields = ()
-    attributes = ('lineno', 'environment')
+    attributes = ("lineno", "environment")
     abstract = True
 
     def __init__(self, *fields, **attributes):
         if self.abstract:
-            raise TypeError('abstract nodes are not instantiable')
+            raise TypeError("abstract nodes are not instantiable")
         if fields:
             if len(fields) != len(self.fields):
                 if not self.fields:
-                    raise TypeError('%r takes 0 arguments' %
-                                    self.__class__.__name__)
-                raise TypeError('%r takes 0 or %d argument%s' % (
-                    self.__class__.__name__,
-                    len(self.fields),
-                    len(self.fields) != 1 and 's' or ''
-                ))
+                    raise TypeError("%r takes 0 arguments" % self.__class__.__name__)
+                raise TypeError(
+                    "%r takes 0 or %d argument%s"
+                    % (
+                        self.__class__.__name__,
+                        len(self.fields),
+                        len(self.fields) != 1 and "s" or "",
+                    )
+                )
             for name, arg in izip(self.fields, fields):
                 setattr(self, name, arg)
         for attr in self.attributes:
             setattr(self, attr, attributes.pop(attr, None))
         if attributes:
-            raise TypeError('unknown attribute %r' %
-                            next(iter(attributes)))
+            raise TypeError("unknown attribute %r" % next(iter(attributes)))
 
     def iter_fields(self, exclude=None, only=None):
         """This method iterates over all fields that are defined and yields
@@ -150,9 +150,11 @@ class Node(with_metaclass(NodeType, object)):
         should be sets or tuples of field names.
         """
         for name in self.fields:
-            if (exclude is only is None) or \
-               (exclude is not None and name not in exclude) or \
-               (only is not None and name in only):
+            if (
+                (exclude is only is None)
+                or (exclude is not None and name not in exclude)
+                or (only is not None and name in only)
+            ):
                 try:
                     yield name, getattr(self, name)
                 except AttributeError:
@@ -197,7 +199,7 @@ class Node(with_metaclass(NodeType, object)):
         todo = deque([self])
         while todo:
             node = todo.popleft()
-            if 'ctx' in node.fields:
+            if "ctx" in node.fields:
                 node.ctx = ctx
             todo.extend(node.iter_child_nodes())
         return self
@@ -207,7 +209,7 @@ class Node(with_metaclass(NodeType, object)):
         todo = deque([self])
         while todo:
             node = todo.popleft()
-            if 'lineno' in node.attributes:
+            if "lineno" in node.attributes:
                 if node.lineno is None or override:
                     node.lineno = lineno
             todo.extend(node.iter_child_nodes())
@@ -223,8 +225,9 @@ class Node(with_metaclass(NodeType, object)):
         return self
 
     def __eq__(self, other):
-        return type(self) is type(other) and \
-               tuple(self.iter_fields()) == tuple(other.iter_fields())
+        return type(self) is type(other) and tuple(self.iter_fields()) == tuple(
+            other.iter_fields()
+        )
 
     def __ne__(self, other):
         return not self.__eq__(other)
@@ -233,10 +236,9 @@ class Node(with_metaclass(NodeType, object)):
     __hash__ = object.__hash__
 
     def __repr__(self):
-        return '%s(%s)' % (
+        return "%s(%s)" % (
             self.__class__.__name__,
-            ', '.join('%s=%r' % (arg, getattr(self, arg, None)) for
-                      arg in self.fields)
+            ", ".join("%s=%r" % (arg, getattr(self, arg, None)) for arg in self.fields),
         )
 
     def dump(self):
@@ -245,37 +247,39 @@ class Node(with_metaclass(NodeType, object)):
                 buf.append(repr(node))
                 return
 
-            buf.append('nodes.%s(' % node.__class__.__name__)
+            buf.append("nodes.%s(" % node.__class__.__name__)
             if not node.fields:
-                buf.append(')')
+                buf.append(")")
                 return
             for idx, field in enumerate(node.fields):
                 if idx:
-                    buf.append(', ')
+                    buf.append(", ")
                 value = getattr(node, field)
                 if isinstance(value, list):
-                    buf.append('[')
+                    buf.append("[")
                     for idx, item in enumerate(value):
                         if idx:
-                            buf.append(', ')
+                            buf.append(", ")
                         _dump(item)
-                    buf.append(']')
+                    buf.append("]")
                 else:
                     _dump(value)
-            buf.append(')')
+            buf.append(")")
+
         buf = []
         _dump(self)
-        return ''.join(buf)
-
+        return "".join(buf)
 
 
 class Stmt(Node):
     """Base node for all statements."""
+
     abstract = True
 
 
 class Helper(Node):
     """Nodes that exist in a specific context only."""
+
     abstract = True
 
 
@@ -283,19 +287,22 @@ class Template(Node):
     """Node that represents a template.  This must be the outermost node that
     is passed to the compiler.
     """
-    fields = ('body',)
+
+    fields = ("body",)
 
 
 class Output(Stmt):
     """A node that holds multiple expressions which are then printed out.
     This is used both for the `print` statement and the regular template data.
     """
-    fields = ('nodes',)
+
+    fields = ("nodes",)
 
 
 class Extends(Stmt):
     """Represents an extends statement."""
-    fields = ('template',)
+
+    fields = ("template",)
 
 
 class For(Stmt):
@@ -306,12 +313,14 @@ class For(Stmt):
 
     For filtered nodes an expression can be stored as `test`, otherwise `None`.
     """
-    fields = ('target', 'iter', 'body', 'else_', 'test', 'recursive')
+
+    fields = ("target", "iter", "body", "else_", "test", "recursive")
 
 
 class If(Stmt):
     """If `test` is true, `body` is rendered, else `else_`."""
-    fields = ('test', 'body', 'elif_', 'else_')
+
+    fields = ("test", "body", "elif_", "else_")
 
 
 class Macro(Stmt):
@@ -319,19 +328,22 @@ class Macro(Stmt):
     arguments and `defaults` a list of defaults if there are any.  `body` is
     a list of nodes for the macro body.
     """
-    fields = ('name', 'args', 'defaults', 'body')
+
+    fields = ("name", "args", "defaults", "body")
 
 
 class CallBlock(Stmt):
     """Like a macro without a name but a call instead.  `call` is called with
     the unnamed macro as `caller` argument this node holds.
     """
-    fields = ('call', 'args', 'defaults', 'body')
+
+    fields = ("call", "args", "defaults", "body")
 
 
 class FilterBlock(Stmt):
     """Node for filter sections."""
-    fields = ('body', 'filter')
+
+    fields = ("body", "filter")
 
 
 class With(Stmt):
@@ -340,22 +352,26 @@ class With(Stmt):
 
     .. versionadded:: 2.9.3
     """
-    fields = ('targets', 'values', 'body')
+
+    fields = ("targets", "values", "body")
 
 
 class Block(Stmt):
     """A node that represents a block."""
-    fields = ('name', 'body', 'scoped')
+
+    fields = ("name", "body", "scoped")
 
 
 class Include(Stmt):
     """A node that represents the include tag."""
-    fields = ('template', 'with_context', 'ignore_missing')
+
+    fields = ("template", "with_context", "ignore_missing")
 
 
 class Import(Stmt):
     """A node that represents the import tag."""
-    fields = ('template', 'target', 'with_context')
+
+    fields = ("template", "target", "with_context")
 
 
 class FromImport(Stmt):
@@ -369,26 +385,31 @@ class FromImport(Stmt):
 
     The list of names may contain tuples if aliases are wanted.
     """
-    fields = ('template', 'names', 'with_context')
+
+    fields = ("template", "names", "with_context")
 
 
 class ExprStmt(Stmt):
     """A statement that evaluates an expression and discards the result."""
-    fields = ('node',)
+
+    fields = ("node",)
 
 
 class Assign(Stmt):
     """Assigns an expression to a target."""
-    fields = ('target', 'node')
+
+    fields = ("target", "node")
 
 
 class AssignBlock(Stmt):
     """Assigns a block to a target."""
-    fields = ('target', 'filter', 'body')
+
+    fields = ("target", "filter", "body")
 
 
 class Expr(Node):
     """Baseclass for all expressions."""
+
     abstract = True
 
     def as_const(self, eval_ctx=None):
@@ -411,15 +432,18 @@ class Expr(Node):
 
 class BinExpr(Expr):
     """Baseclass for all binary expressions."""
-    fields = ('left', 'right')
+
+    fields = ("left", "right")
     operator = None
     abstract = True
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
         # intercepted operators cannot be folded at compile time
-        if self.environment.sandboxed and \
-           self.operator in self.environment.intercepted_binops:
+        if (
+            self.environment.sandboxed
+            and self.operator in self.environment.intercepted_binops
+        ):
             raise Impossible()
         f = _binop_to_func[self.operator]
         try:
@@ -430,15 +454,18 @@ class BinExpr(Expr):
 
 class UnaryExpr(Expr):
     """Baseclass for all unary expressions."""
-    fields = ('node',)
+
+    fields = ("node",)
     operator = None
     abstract = True
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
         # intercepted operators cannot be folded at compile time
-        if self.environment.sandboxed and \
-           self.operator in self.environment.intercepted_unops:
+        if (
+            self.environment.sandboxed
+            and self.operator in self.environment.intercepted_unops
+        ):
             raise Impossible()
         f = _uaop_to_func[self.operator]
         try:
@@ -455,16 +482,17 @@ class Name(Expr):
     -   `load`: load that name
     -   `param`: like `store` but if the name was defined as function parameter.
     """
-    fields = ('name', 'ctx')
+
+    fields = ("name", "ctx")
 
     def can_assign(self):
-        return self.name not in ('true', 'false', 'none',
-                                 'True', 'False', 'None')
+        return self.name not in ("true", "false", "none", "True", "False", "None")
 
 
 class NSRef(Expr):
     """Reference to a namespace value assignment"""
-    fields = ('name', 'attr')
+
+    fields = ("name", "attr")
 
     def can_assign(self):
         # We don't need any special checks here; NSRef assignments have a
@@ -476,6 +504,7 @@ class NSRef(Expr):
 
 class Literal(Expr):
     """Baseclass for literals."""
+
     abstract = True
 
 
@@ -485,14 +514,18 @@ class Const(Literal):
     complex values such as lists too.  Only constants with a safe
     representation (objects where ``eval(repr(x)) == x`` is true).
     """
-    fields = ('value',)
+
+    fields = ("value",)
 
     def as_const(self, eval_ctx=None):
         rv = self.value
-        if PY2 and type(rv) is text_type and \
-           self.environment.policies['compiler.ascii_str']:
+        if (
+            PY2
+            and type(rv) is text_type
+            and self.environment.policies["compiler.ascii_str"]
+        ):
             try:
-                rv = rv.encode('ascii')
+                rv = rv.encode("ascii")
             except UnicodeError:
                 pass
         return rv
@@ -504,6 +537,7 @@ class Const(Literal):
         an `Impossible` exception.
         """
         from .compiler import has_safe_repr
+
         if not has_safe_repr(value):
             raise Impossible()
         return cls(value, lineno=lineno, environment=environment)
@@ -511,7 +545,8 @@ class Const(Literal):
 
 class TemplateData(Literal):
     """A constant template string."""
-    fields = ('data',)
+
+    fields = ("data",)
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -527,7 +562,8 @@ class Tuple(Literal):
     for subscripts.  Like for :class:`Name` `ctx` specifies if the tuple
     is used for loading the names or storing.
     """
-    fields = ('items', 'ctx')
+
+    fields = ("items", "ctx")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -542,7 +578,8 @@ class Tuple(Literal):
 
 class List(Literal):
     """Any list literal such as ``[1, 2, 3]``"""
-    fields = ('items',)
+
+    fields = ("items",)
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -553,7 +590,8 @@ class Dict(Literal):
     """Any dict literal such as ``{1: 2, 3: 4}``.  The items must be a list of
     :class:`Pair` nodes.
     """
-    fields = ('items',)
+
+    fields = ("items",)
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -562,7 +600,8 @@ class Dict(Literal):
 
 class Pair(Helper):
     """A key, value pair for dicts."""
-    fields = ('key', 'value')
+
+    fields = ("key", "value")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -571,7 +610,8 @@ class Pair(Helper):
 
 class Keyword(Helper):
     """A key, value pair for keyword arguments where key is a string."""
-    fields = ('key', 'value')
+
+    fields = ("key", "value")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -582,7 +622,8 @@ class CondExpr(Expr):
     """A conditional expression (inline if expression).  (``{{
     foo if bar else baz }}``)
     """
-    fields = ('test', 'expr1', 'expr2')
+
+    fields = ("test", "expr1", "expr2")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -623,7 +664,7 @@ class Filter(Expr):
     filtered.  Buffers are created by macros and filter blocks.
     """
 
-    fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+    fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -638,23 +679,22 @@ class Filter(Expr):
         # python 3.  because of that, do not rename filter_ to filter!
         filter_ = self.environment.filters.get(self.name)
 
-        if filter_ is None or getattr(filter_, 'contextfilter', False):
+        if filter_ is None or getattr(filter_, "contextfilter", False):
             raise Impossible()
 
         # We cannot constant handle async filters, so we need to make sure
         # to not go down this path.
-        if (
-            eval_ctx.environment.is_async
-            and getattr(filter_, 'asyncfiltervariant', False)
+        if eval_ctx.environment.is_async and getattr(
+            filter_, "asyncfiltervariant", False
         ):
             raise Impossible()
 
         args, kwargs = args_as_const(self, eval_ctx)
         args.insert(0, self.node.as_const(eval_ctx))
 
-        if getattr(filter_, 'evalcontextfilter', False):
+        if getattr(filter_, "evalcontextfilter", False):
             args.insert(0, eval_ctx)
-        elif getattr(filter_, 'environmentfilter', False):
+        elif getattr(filter_, "environmentfilter", False):
             args.insert(0, self.environment)
 
         try:
@@ -668,7 +708,7 @@ class Test(Expr):
     rest of the fields are the same as for :class:`Call`.
     """
 
-    fields = ('node', 'name', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+    fields = ("node", "name", "args", "kwargs", "dyn_args", "dyn_kwargs")
 
     def as_const(self, eval_ctx=None):
         test = self.environment.tests.get(self.name)
@@ -693,20 +733,23 @@ class Call(Expr):
     node for dynamic positional (``*args``) or keyword (``**kwargs``)
     arguments.
     """
-    fields = ('node', 'args', 'kwargs', 'dyn_args', 'dyn_kwargs')
+
+    fields = ("node", "args", "kwargs", "dyn_args", "dyn_kwargs")
 
 
 class Getitem(Expr):
     """Get an attribute or item from an expression and prefer the item."""
-    fields = ('node', 'arg', 'ctx')
+
+    fields = ("node", "arg", "ctx")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
-        if self.ctx != 'load':
+        if self.ctx != "load":
             raise Impossible()
         try:
-            return self.environment.getitem(self.node.as_const(eval_ctx),
-                                            self.arg.as_const(eval_ctx))
+            return self.environment.getitem(
+                self.node.as_const(eval_ctx), self.arg.as_const(eval_ctx)
+            )
         except Exception:
             raise Impossible()
 
@@ -718,15 +761,15 @@ class Getattr(Expr):
     """Get an attribute or item from an expression that is a ascii-only
     bytestring and prefer the attribute.
     """
-    fields = ('node', 'attr', 'ctx')
+
+    fields = ("node", "attr", "ctx")
 
     def as_const(self, eval_ctx=None):
-        if self.ctx != 'load':
+        if self.ctx != "load":
             raise Impossible()
         try:
             eval_ctx = get_eval_context(self, eval_ctx)
-            return self.environment.getattr(self.node.as_const(eval_ctx),
-                                            self.attr)
+            return self.environment.getattr(self.node.as_const(eval_ctx), self.attr)
         except Exception:
             raise Impossible()
 
@@ -738,14 +781,17 @@ class Slice(Expr):
     """Represents a slice object.  This must only be used as argument for
     :class:`Subscript`.
     """
-    fields = ('start', 'stop', 'step')
+
+    fields = ("start", "stop", "step")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
+
         def const(obj):
             if obj is None:
                 return None
             return obj.as_const(eval_ctx)
+
         return slice(const(self.start), const(self.stop), const(self.step))
 
 
@@ -753,18 +799,20 @@ class Concat(Expr):
     """Concatenates the list of expressions provided after converting them to
     unicode.
     """
-    fields = ('nodes',)
+
+    fields = ("nodes",)
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
-        return ''.join(text_type(x.as_const(eval_ctx)) for x in self.nodes)
+        return "".join(text_type(x.as_const(eval_ctx)) for x in self.nodes)
 
 
 class Compare(Expr):
     """Compares an expression with some other expressions.  `ops` must be a
     list of :class:`Operand`\\s.
     """
-    fields = ('expr', 'ops')
+
+    fields = ("expr", "ops")
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -787,54 +835,67 @@ class Compare(Expr):
 
 class Operand(Helper):
     """Holds an operator and an expression."""
-    fields = ('op', 'expr')
+
+    fields = ("op", "expr")
+
 
 if __debug__:
-    Operand.__doc__ += '\nThe following operators are available: ' + \
-        ', '.join(sorted('``%s``' % x for x in set(_binop_to_func) |
-                  set(_uaop_to_func) | set(_cmpop_to_func)))
+    Operand.__doc__ += "\nThe following operators are available: " + ", ".join(
+        sorted(
+            "``%s``" % x
+            for x in set(_binop_to_func) | set(_uaop_to_func) | set(_cmpop_to_func)
+        )
+    )
 
 
 class Mul(BinExpr):
     """Multiplies the left with the right node."""
-    operator = '*'
+
+    operator = "*"
 
 
 class Div(BinExpr):
     """Divides the left by the right node."""
-    operator = '/'
+
+    operator = "/"
 
 
 class FloorDiv(BinExpr):
     """Divides the left by the right node and truncates conver the
     result into an integer by truncating.
     """
-    operator = '//'
+
+    operator = "//"
 
 
 class Add(BinExpr):
     """Add the left to the right node."""
-    operator = '+'
+
+    operator = "+"
 
 
 class Sub(BinExpr):
     """Subtract the right from the left node."""
-    operator = '-'
+
+    operator = "-"
 
 
 class Mod(BinExpr):
     """Left modulo right."""
-    operator = '%'
+
+    operator = "%"
 
 
 class Pow(BinExpr):
     """Left to the power of right."""
-    operator = '**'
+
+    operator = "**"
 
 
 class And(BinExpr):
     """Short circuited AND."""
-    operator = 'and'
+
+    operator = "and"
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -843,7 +904,8 @@ class And(BinExpr):
 
 class Or(BinExpr):
     """Short circuited OR."""
-    operator = 'or'
+
+    operator = "or"
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -852,17 +914,20 @@ class Or(BinExpr):
 
 class Not(UnaryExpr):
     """Negate the expression."""
-    operator = 'not'
+
+    operator = "not"
 
 
 class Neg(UnaryExpr):
     """Make the expression negative."""
-    operator = '-'
+
+    operator = "-"
 
 
 class Pos(UnaryExpr):
     """Make the expression positive (noop for most expressions)"""
-    operator = '+'
+
+    operator = "+"
 
 
 # Helpers for extensions
@@ -872,7 +937,8 @@ class EnvironmentAttribute(Expr):
     """Loads an attribute from the environment object.  This is useful for
     extensions that want to call a callback stored on the environment.
     """
-    fields = ('name',)
+
+    fields = ("name",)
 
 
 class ExtensionAttribute(Expr):
@@ -882,7 +948,8 @@ class ExtensionAttribute(Expr):
     This node is usually constructed by calling the
     :meth:`~jinja2.ext.Extension.attr` method on an extension.
     """
-    fields = ('identifier', 'name')
+
+    fields = ("identifier", "name")
 
 
 class ImportedName(Expr):
@@ -891,7 +958,8 @@ class ImportedName(Expr):
     function from the cgi module on evaluation.  Imports are optimized by the
     compiler so there is no need to assign them to local variables.
     """
-    fields = ('importname',)
+
+    fields = ("importname",)
 
 
 class InternalName(Expr):
@@ -901,16 +969,20 @@ class InternalName(Expr):
     a new identifier for you.  This identifier is not available from the
     template and is not threated specially by the compiler.
     """
-    fields = ('name',)
+
+    fields = ("name",)
 
     def __init__(self):
-        raise TypeError('Can\'t create internal names.  Use the '
-                        '`free_identifier` method on a parser.')
+        raise TypeError(
+            "Can't create internal names.  Use the "
+            "`free_identifier` method on a parser."
+        )
 
 
 class MarkSafe(Expr):
     """Mark the wrapped expression as safe (wrap it as `Markup`)."""
-    fields = ('expr',)
+
+    fields = ("expr",)
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -923,7 +995,8 @@ class MarkSafeIfAutoescape(Expr):
 
     .. versionadded:: 2.5
     """
-    fields = ('expr',)
+
+    fields = ("expr",)
 
     def as_const(self, eval_ctx=None):
         eval_ctx = get_eval_context(self, eval_ctx)
@@ -972,7 +1045,8 @@ class Break(Stmt):
 
 class Scope(Stmt):
     """An artificial scope."""
-    fields = ('body',)
+
+    fields = ("body",)
 
 
 class OverlayScope(Stmt):
@@ -988,7 +1062,8 @@ class OverlayScope(Stmt):
 
     .. versionadded:: 2.10
     """
-    fields = ('context', 'body')
+
+    fields = ("context", "body")
 
 
 class EvalContextModifier(Stmt):
@@ -999,7 +1074,8 @@ class EvalContextModifier(Stmt):
 
         EvalContextModifier(options=[Keyword('autoescape', Const(True))])
     """
-    fields = ('options',)
+
+    fields = ("options",)
 
 
 class ScopedEvalContextModifier(EvalContextModifier):
@@ -1007,10 +1083,14 @@ class ScopedEvalContextModifier(EvalContextModifier):
     :class:`EvalContextModifier` but will only modify the
     :class:`~jinja2.nodes.EvalContext` for nodes in the :attr:`body`.
     """
-    fields = ('body',)
+
+    fields = ("body",)
 
 
 # make sure nobody creates custom nodes
 def _failing_new(*args, **kwargs):
-    raise TypeError('can\'t create custom node types')
-NodeType.__new__ = staticmethod(_failing_new); del _failing_new
+    raise TypeError("can't create custom node types")
+
+
+NodeType.__new__ = staticmethod(_failing_new)
+del _failing_new
index 3759761957ff8c1b490d1e0525c43a1cc777da37..648c3fd1acaafba8fccacfbf775b6912356b87c1 100644 (file)
@@ -15,18 +15,31 @@ from .exceptions import TemplateSyntaxError
 from .lexer import describe_token
 from .lexer import describe_token_expr
 
-_statement_keywords = frozenset(['for', 'if', 'block', 'extends', 'print',
-                                 'macro', 'include', 'from', 'import',
-                                 'set', 'with', 'autoescape'])
-_compare_operators = frozenset(['eq', 'ne', 'lt', 'lteq', 'gt', 'gteq'])
+_statement_keywords = frozenset(
+    [
+        "for",
+        "if",
+        "block",
+        "extends",
+        "print",
+        "macro",
+        "include",
+        "from",
+        "import",
+        "set",
+        "with",
+        "autoescape",
+    ]
+)
+_compare_operators = frozenset(["eq", "ne", "lt", "lteq", "gt", "gteq"])
 
 _math_nodes = {
-    'add': nodes.Add,
-    'sub': nodes.Sub,
-    'mul': nodes.Mul,
-    'div': nodes.Div,
-    'floordiv': nodes.FloorDiv,
-    'mod': nodes.Mod,
+    "add": nodes.Add,
+    "sub": nodes.Sub,
+    "mul": nodes.Mul,
+    "div": nodes.Div,
+    "floordiv": nodes.FloorDiv,
+    "mod": nodes.Mod,
 }
 
 
@@ -35,8 +48,7 @@ class Parser(object):
     extensions and can be used to parse expressions or statements.
     """
 
-    def __init__(self, environment, source, name=None, filename=None,
-                 state=None):
+    def __init__(self, environment, source, name=None, filename=None, state=None):
         self.environment = environment
         self.stream = environment._tokenize(source, name, filename, state)
         self.name = name
@@ -64,31 +76,37 @@ class Parser(object):
         for exprs in end_token_stack:
             expected.extend(imap(describe_token_expr, exprs))
         if end_token_stack:
-            currently_looking = ' or '.join(
-                "'%s'" % describe_token_expr(expr)
-                for expr in end_token_stack[-1])
+            currently_looking = " or ".join(
+                "'%s'" % describe_token_expr(expr) for expr in end_token_stack[-1]
+            )
         else:
             currently_looking = None
 
         if name is None:
-            message = ['Unexpected end of template.']
+            message = ["Unexpected end of template."]
         else:
-            message = ['Encountered unknown tag \'%s\'.' % name]
+            message = ["Encountered unknown tag '%s'." % name]
 
         if currently_looking:
             if name is not None and name in expected:
-                message.append('You probably made a nesting mistake. Jinja '
-                               'is expecting this tag, but currently looking '
-                               'for %s.' % currently_looking)
+                message.append(
+                    "You probably made a nesting mistake. Jinja "
+                    "is expecting this tag, but currently looking "
+                    "for %s." % currently_looking
+                )
             else:
-                message.append('Jinja was looking for the following tags: '
-                               '%s.' % currently_looking)
+                message.append(
+                    "Jinja was looking for the following tags: "
+                    "%s." % currently_looking
+                )
 
         if self._tag_stack:
-            message.append('The innermost block that needs to be '
-                           'closed is \'%s\'.' % self._tag_stack[-1])
+            message.append(
+                "The innermost block that needs to be "
+                "closed is '%s'." % self._tag_stack[-1]
+            )
 
-        self.fail(' '.join(message), lineno)
+        self.fail(" ".join(message), lineno)
 
     def fail_unknown_tag(self, name, lineno=None):
         """Called if the parser encounters an unknown tag.  Tries to fail
@@ -106,7 +124,7 @@ class Parser(object):
 
     def is_tuple_end(self, extra_end_rules=None):
         """Are we at the end of a tuple?"""
-        if self.stream.current.type in ('variable_end', 'block_end', 'rparen'):
+        if self.stream.current.type in ("variable_end", "block_end", "rparen"):
             return True
         elif extra_end_rules is not None:
             return self.stream.current.test_any(extra_end_rules)
@@ -116,22 +134,22 @@ class Parser(object):
         """Return a new free identifier as :class:`~jinja2.nodes.InternalName`."""
         self._last_identifier += 1
         rv = object.__new__(nodes.InternalName)
-        nodes.Node.__init__(rv, 'fi%d' % self._last_identifier, lineno=lineno)
+        nodes.Node.__init__(rv, "fi%d" % self._last_identifier, lineno=lineno)
         return rv
 
     def parse_statement(self):
         """Parse a single statement."""
         token = self.stream.current
-        if token.type != 'name':
-            self.fail('tag name expected', token.lineno)
+        if token.type != "name":
+            self.fail("tag name expected", token.lineno)
         self._tag_stack.append(token.value)
         pop_tag = True
         try:
             if token.value in _statement_keywords:
-                return getattr(self, 'parse_' + self.stream.current.value)()
-            if token.value == 'call':
+                return getattr(self, "parse_" + self.stream.current.value)()
+            if token.value == "call":
                 return self.parse_call_block()
-            if token.value == 'filter':
+            if token.value == "filter":
                 return self.parse_filter_block()
             ext = self.extensions.get(token.value)
             if ext is not None:
@@ -158,16 +176,16 @@ class Parser(object):
         can be set to `True` and the end token is removed.
         """
         # the first token may be a colon for python compatibility
-        self.stream.skip_if('colon')
+        self.stream.skip_if("colon")
 
         # in the future it would be possible to add whole code sections
         # by adding some sort of end of statement token and parsing those here.
-        self.stream.expect('block_end')
+        self.stream.expect("block_end")
         result = self.subparse(end_tokens)
 
         # we reached the end of the template too early, the subparser
         # does not check for this, so we do that now
-        if self.stream.current.type == 'eof':
+        if self.stream.current.type == "eof":
             self.fail_eof(end_tokens)
 
         if drop_needle:
@@ -178,50 +196,47 @@ class Parser(object):
         """Parse an assign statement."""
         lineno = next(self.stream).lineno
         target = self.parse_assign_target(with_namespace=True)
-        if self.stream.skip_if('assign'):
+        if self.stream.skip_if("assign"):
             expr = self.parse_tuple()
             return nodes.Assign(target, expr, lineno=lineno)
         filter_node = self.parse_filter(None)
-        body = self.parse_statements(('name:endset',),
-                                     drop_needle=True)
+        body = self.parse_statements(("name:endset",), drop_needle=True)
         return nodes.AssignBlock(target, filter_node, body, lineno=lineno)
 
     def parse_for(self):
         """Parse a for loop."""
-        lineno = self.stream.expect('name:for').lineno
-        target = self.parse_assign_target(extra_end_rules=('name:in',))
-        self.stream.expect('name:in')
-        iter = self.parse_tuple(with_condexpr=False,
-                                extra_end_rules=('name:recursive',))
+        lineno = self.stream.expect("name:for").lineno
+        target = self.parse_assign_target(extra_end_rules=("name:in",))
+        self.stream.expect("name:in")
+        iter = self.parse_tuple(
+            with_condexpr=False, extra_end_rules=("name:recursive",)
+        )
         test = None
-        if self.stream.skip_if('name:if'):
+        if self.stream.skip_if("name:if"):
             test = self.parse_expression()
-        recursive = self.stream.skip_if('name:recursive')
-        body = self.parse_statements(('name:endfor', 'name:else'))
-        if next(self.stream).value == 'endfor':
+        recursive = self.stream.skip_if("name:recursive")
+        body = self.parse_statements(("name:endfor", "name:else"))
+        if next(self.stream).value == "endfor":
             else_ = []
         else:
-            else_ = self.parse_statements(('name:endfor',), drop_needle=True)
-        return nodes.For(target, iter, body, else_, test,
-                         recursive, lineno=lineno)
+            else_ = self.parse_statements(("name:endfor",), drop_needle=True)
+        return nodes.For(target, iter, body, else_, test, recursive, lineno=lineno)
 
     def parse_if(self):
         """Parse an if construct."""
-        node = result = nodes.If(lineno=self.stream.expect('name:if').lineno)
+        node = result = nodes.If(lineno=self.stream.expect("name:if").lineno)
         while 1:
             node.test = self.parse_tuple(with_condexpr=False)
-            node.body = self.parse_statements(('name:elif', 'name:else',
-                                               'name:endif'))
+            node.body = self.parse_statements(("name:elif", "name:else", "name:endif"))
             node.elif_ = []
             node.else_ = []
             token = next(self.stream)
-            if token.test('name:elif'):
+            if token.test("name:elif"):
                 node = nodes.If(lineno=self.stream.current.lineno)
                 result.elif_.append(node)
                 continue
-            elif token.test('name:else'):
-                result.else_ = self.parse_statements(('name:endif',),
-                                                     drop_needle=True)
+            elif token.test("name:else"):
+                result.else_ = self.parse_statements(("name:endif",), drop_needle=True)
             break
         return result
 
@@ -229,45 +244,43 @@ class Parser(object):
         node = nodes.With(lineno=next(self.stream).lineno)
         targets = []
         values = []
-        while self.stream.current.type != 'block_end':
+        while self.stream.current.type != "block_end":
             lineno = self.stream.current.lineno
             if targets:
-                self.stream.expect('comma')
+                self.stream.expect("comma")
             target = self.parse_assign_target()
-            target.set_ctx('param')
+            target.set_ctx("param")
             targets.append(target)
-            self.stream.expect('assign')
+            self.stream.expect("assign")
             values.append(self.parse_expression())
         node.targets = targets
         node.values = values
-        node.body = self.parse_statements(('name:endwith',),
-                                          drop_needle=True)
+        node.body = self.parse_statements(("name:endwith",), drop_needle=True)
         return node
 
     def parse_autoescape(self):
         node = nodes.ScopedEvalContextModifier(lineno=next(self.stream).lineno)
-        node.options = [
-            nodes.Keyword('autoescape', self.parse_expression())
-        ]
-        node.body = self.parse_statements(('name:endautoescape',),
-                                            drop_needle=True)
+        node.options = [nodes.Keyword("autoescape", self.parse_expression())]
+        node.body = self.parse_statements(("name:endautoescape",), drop_needle=True)
         return nodes.Scope([node])
 
     def parse_block(self):
         node = nodes.Block(lineno=next(self.stream).lineno)
-        node.name = self.stream.expect('name').value
-        node.scoped = self.stream.skip_if('name:scoped')
+        node.name = self.stream.expect("name").value
+        node.scoped = self.stream.skip_if("name:scoped")
 
         # common problem people encounter when switching from django
         # to jinja.  we do not support hyphens in block names, so let's
         # raise a nicer error message in that case.
-        if self.stream.current.type == 'sub':
-            self.fail('Block names in Jinja have to be valid Python '
-                      'identifiers and may not contain hyphens, use an '
-                      'underscore instead.')
-
-        node.body = self.parse_statements(('name:endblock',), drop_needle=True)
-        self.stream.skip_if('name:' + node.name)
+        if self.stream.current.type == "sub":
+            self.fail(
+                "Block names in Jinja have to be valid Python "
+                "identifiers and may not contain hyphens, use an "
+                "underscore instead."
+            )
+
+        node.body = self.parse_statements(("name:endblock",), drop_needle=True)
+        self.stream.skip_if("name:" + node.name)
         return node
 
     def parse_extends(self):
@@ -276,9 +289,10 @@ class Parser(object):
         return node
 
     def parse_import_context(self, node, default):
-        if self.stream.current.test_any('name:with', 'name:without') and \
-           self.stream.look().test('name:context'):
-            node.with_context = next(self.stream).value == 'with'
+        if self.stream.current.test_any(
+            "name:with", "name:without"
+        ) and self.stream.look().test("name:context"):
+            node.with_context = next(self.stream).value == "with"
             self.stream.skip()
         else:
             node.with_context = default
@@ -287,8 +301,9 @@ class Parser(object):
     def parse_include(self):
         node = nodes.Include(lineno=next(self.stream).lineno)
         node.template = self.parse_expression()
-        if self.stream.current.test('name:ignore') and \
-           self.stream.look().test('name:missing'):
+        if self.stream.current.test("name:ignore") and self.stream.look().test(
+            "name:missing"
+        ):
             node.ignore_missing = True
             self.stream.skip(2)
         else:
@@ -298,67 +313,71 @@ class Parser(object):
     def parse_import(self):
         node = nodes.Import(lineno=next(self.stream).lineno)
         node.template = self.parse_expression()
-        self.stream.expect('name:as')
+        self.stream.expect("name:as")
         node.target = self.parse_assign_target(name_only=True).name
         return self.parse_import_context(node, False)
 
     def parse_from(self):
         node = nodes.FromImport(lineno=next(self.stream).lineno)
         node.template = self.parse_expression()
-        self.stream.expect('name:import')
+        self.stream.expect("name:import")
         node.names = []
 
         def parse_context():
-            if self.stream.current.value in ('with', 'without') and \
-               self.stream.look().test('name:context'):
-                node.with_context = next(self.stream).value == 'with'
+            if self.stream.current.value in (
+                "with",
+                "without",
+            ) and self.stream.look().test("name:context"):
+                node.with_context = next(self.stream).value == "with"
                 self.stream.skip()
                 return True
             return False
 
         while 1:
             if node.names:
-                self.stream.expect('comma')
-            if self.stream.current.type == 'name':
+                self.stream.expect("comma")
+            if self.stream.current.type == "name":
                 if parse_context():
                     break
                 target = self.parse_assign_target(name_only=True)
-                if target.name.startswith('_'):
-                    self.fail('names starting with an underline can not '
-                              'be imported', target.lineno,
-                              exc=TemplateAssertionError)
-                if self.stream.skip_if('name:as'):
+                if target.name.startswith("_"):
+                    self.fail(
+                        "names starting with an underline can not be imported",
+                        target.lineno,
+                        exc=TemplateAssertionError,
+                    )
+                if self.stream.skip_if("name:as"):
                     alias = self.parse_assign_target(name_only=True)
                     node.names.append((target.name, alias.name))
                 else:
                     node.names.append(target.name)
-                if parse_context() or self.stream.current.type != 'comma':
+                if parse_context() or self.stream.current.type != "comma":
                     break
             else:
-                self.stream.expect('name')
-        if not hasattr(node, 'with_context'):
+                self.stream.expect("name")
+        if not hasattr(node, "with_context"):
             node.with_context = False
         return node
 
     def parse_signature(self, node):
         node.args = args = []
         node.defaults = defaults = []
-        self.stream.expect('lparen')
-        while self.stream.current.type != 'rparen':
+        self.stream.expect("lparen")
+        while self.stream.current.type != "rparen":
             if args:
-                self.stream.expect('comma')
+                self.stream.expect("comma")
             arg = self.parse_assign_target(name_only=True)
-            arg.set_ctx('param')
-            if self.stream.skip_if('assign'):
+            arg.set_ctx("param")
+            if self.stream.skip_if("assign"):
                 defaults.append(self.parse_expression())
             elif defaults:
-                self.fail('non-default argument follows default argument')
+                self.fail("non-default argument follows default argument")
             args.append(arg)
-        self.stream.expect('rparen')
+        self.stream.expect("rparen")
 
     def parse_call_block(self):
         node = nodes.CallBlock(lineno=next(self.stream).lineno)
-        if self.stream.current.type == 'lparen':
+        if self.stream.current.type == "lparen":
             self.parse_signature(node)
         else:
             node.args = []
@@ -366,36 +385,39 @@ class Parser(object):
 
         node.call = self.parse_expression()
         if not isinstance(node.call, nodes.Call):
-            self.fail('expected call', node.lineno)
-        node.body = self.parse_statements(('name:endcall',), drop_needle=True)
+            self.fail("expected call", node.lineno)
+        node.body = self.parse_statements(("name:endcall",), drop_needle=True)
         return node
 
     def parse_filter_block(self):
         node = nodes.FilterBlock(lineno=next(self.stream).lineno)
         node.filter = self.parse_filter(None, start_inline=True)
-        node.body = self.parse_statements(('name:endfilter',),
-                                          drop_needle=True)
+        node.body = self.parse_statements(("name:endfilter",), drop_needle=True)
         return node
 
     def parse_macro(self):
         node = nodes.Macro(lineno=next(self.stream).lineno)
         node.name = self.parse_assign_target(name_only=True).name
         self.parse_signature(node)
-        node.body = self.parse_statements(('name:endmacro',),
-                                          drop_needle=True)
+        node.body = self.parse_statements(("name:endmacro",), drop_needle=True)
         return node
 
     def parse_print(self):
         node = nodes.Output(lineno=next(self.stream).lineno)
         node.nodes = []
-        while self.stream.current.type != 'block_end':
+        while self.stream.current.type != "block_end":
             if node.nodes:
-                self.stream.expect('comma')
+                self.stream.expect("comma")
             node.nodes.append(self.parse_expression())
         return node
 
-    def parse_assign_target(self, with_tuple=True, name_only=False,
-                            extra_end_rules=None, with_namespace=False):
+    def parse_assign_target(
+        self,
+        with_tuple=True,
+        name_only=False,
+        extra_end_rules=None,
+        with_namespace=False,
+    ):
         """Parse an assignment target.  As Jinja allows assignments to
         tuples, this function can parse all allowed assignment targets.  Per
         default assignments to tuples are parsed, that can be disable however
@@ -404,24 +426,26 @@ class Parser(object):
         parameter is forwarded to the tuple parsing function.  If
         `with_namespace` is enabled, a namespace assignment may be parsed.
         """
-        if with_namespace and self.stream.look().type == 'dot':
-            token = self.stream.expect('name')
+        if with_namespace and self.stream.look().type == "dot":
+            token = self.stream.expect("name")
             next(self.stream)  # dot
-            attr = self.stream.expect('name')
+            attr = self.stream.expect("name")
             target = nodes.NSRef(token.value, attr.value, lineno=token.lineno)
         elif name_only:
-            token = self.stream.expect('name')
-            target = nodes.Name(token.value, 'store', lineno=token.lineno)
+            token = self.stream.expect("name")
+            target = nodes.Name(token.value, "store", lineno=token.lineno)
         else:
             if with_tuple:
-                target = self.parse_tuple(simplified=True,
-                                          extra_end_rules=extra_end_rules)
+                target = self.parse_tuple(
+                    simplified=True, extra_end_rules=extra_end_rules
+                )
             else:
                 target = self.parse_primary()
-            target.set_ctx('store')
+            target.set_ctx("store")
         if not target.can_assign():
-            self.fail('can\'t assign to %r' % target.__class__.
-                      __name__.lower(), target.lineno)
+            self.fail(
+                "can't assign to %r" % target.__class__.__name__.lower(), target.lineno
+            )
         return target
 
     def parse_expression(self, with_condexpr=True):
@@ -436,9 +460,9 @@ class Parser(object):
     def parse_condexpr(self):
         lineno = self.stream.current.lineno
         expr1 = self.parse_or()
-        while self.stream.skip_if('name:if'):
+        while self.stream.skip_if("name:if"):
             expr2 = self.parse_or()
-            if self.stream.skip_if('name:else'):
+            if self.stream.skip_if("name:else"):
                 expr3 = self.parse_condexpr()
             else:
                 expr3 = None
@@ -449,7 +473,7 @@ class Parser(object):
     def parse_or(self):
         lineno = self.stream.current.lineno
         left = self.parse_and()
-        while self.stream.skip_if('name:or'):
+        while self.stream.skip_if("name:or"):
             right = self.parse_and()
             left = nodes.Or(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
@@ -458,14 +482,14 @@ class Parser(object):
     def parse_and(self):
         lineno = self.stream.current.lineno
         left = self.parse_not()
-        while self.stream.skip_if('name:and'):
+        while self.stream.skip_if("name:and"):
             right = self.parse_not()
             left = nodes.And(left, right, lineno=lineno)
             lineno = self.stream.current.lineno
         return left
 
     def parse_not(self):
-        if self.stream.current.test('name:not'):
+        if self.stream.current.test("name:not"):
             lineno = next(self.stream).lineno
             return nodes.Not(self.parse_not(), lineno=lineno)
         return self.parse_compare()
@@ -479,12 +503,13 @@ class Parser(object):
             if token_type in _compare_operators:
                 next(self.stream)
                 ops.append(nodes.Operand(token_type, self.parse_math1()))
-            elif self.stream.skip_if('name:in'):
-                ops.append(nodes.Operand('in', self.parse_math1()))
-            elif (self.stream.current.test('name:not') and
-                  self.stream.look().test('name:in')):
+            elif self.stream.skip_if("name:in"):
+                ops.append(nodes.Operand("in", self.parse_math1()))
+            elif self.stream.current.test("name:not") and self.stream.look().test(
+                "name:in"
+            ):
                 self.stream.skip(2)
-                ops.append(nodes.Operand('notin', self.parse_math1()))
+                ops.append(nodes.Operand("notin", self.parse_math1()))
             else:
                 break
             lineno = self.stream.current.lineno
@@ -495,7 +520,7 @@ class Parser(object):
     def parse_math1(self):
         lineno = self.stream.current.lineno
         left = self.parse_concat()
-        while self.stream.current.type in ('add', 'sub'):
+        while self.stream.current.type in ("add", "sub"):
             cls = _math_nodes[self.stream.current.type]
             next(self.stream)
             right = self.parse_concat()
@@ -506,7 +531,7 @@ class Parser(object):
     def parse_concat(self):
         lineno = self.stream.current.lineno
         args = [self.parse_math2()]
-        while self.stream.current.type == 'tilde':
+        while self.stream.current.type == "tilde":
             next(self.stream)
             args.append(self.parse_math2())
         if len(args) == 1:
@@ -516,7 +541,7 @@ class Parser(object):
     def parse_math2(self):
         lineno = self.stream.current.lineno
         left = self.parse_pow()
-        while self.stream.current.type in ('mul', 'div', 'floordiv', 'mod'):
+        while self.stream.current.type in ("mul", "div", "floordiv", "mod"):
             cls = _math_nodes[self.stream.current.type]
             next(self.stream)
             right = self.parse_pow()
@@ -527,7 +552,7 @@ class Parser(object):
     def parse_pow(self):
         lineno = self.stream.current.lineno
         left = self.parse_unary()
-        while self.stream.current.type == 'pow':
+        while self.stream.current.type == "pow":
             next(self.stream)
             right = self.parse_unary()
             left = nodes.Pow(left, right, lineno=lineno)
@@ -537,10 +562,10 @@ class Parser(object):
     def parse_unary(self, with_filter=True):
         token_type = self.stream.current.type
         lineno = self.stream.current.lineno
-        if token_type == 'sub':
+        if token_type == "sub":
             next(self.stream)
             node = nodes.Neg(self.parse_unary(False), lineno=lineno)
-        elif token_type == 'add':
+        elif token_type == "add":
             next(self.stream)
             node = nodes.Pos(self.parse_unary(False), lineno=lineno)
         else:
@@ -552,40 +577,44 @@ class Parser(object):
 
     def parse_primary(self):
         token = self.stream.current
-        if token.type == 'name':
-            if token.value in ('true', 'false', 'True', 'False'):
-                node = nodes.Const(token.value in ('true', 'True'),
-                                   lineno=token.lineno)
-            elif token.value in ('none', 'None'):
+        if token.type == "name":
+            if token.value in ("true", "false", "True", "False"):
+                node = nodes.Const(token.value in ("true", "True"), lineno=token.lineno)
+            elif token.value in ("none", "None"):
                 node = nodes.Const(None, lineno=token.lineno)
             else:
-                node = nodes.Name(token.value, 'load', lineno=token.lineno)
+                node = nodes.Name(token.value, "load", lineno=token.lineno)
             next(self.stream)
-        elif token.type == 'string':
+        elif token.type == "string":
             next(self.stream)
             buf = [token.value]
             lineno = token.lineno
-            while self.stream.current.type == 'string':
+            while self.stream.current.type == "string":
                 buf.append(self.stream.current.value)
                 next(self.stream)
-            node = nodes.Const(''.join(buf), lineno=lineno)
-        elif token.type in ('integer', 'float'):
+            node = nodes.Const("".join(buf), lineno=lineno)
+        elif token.type in ("integer", "float"):
             next(self.stream)
             node = nodes.Const(token.value, lineno=token.lineno)
-        elif token.type == 'lparen':
+        elif token.type == "lparen":
             next(self.stream)
             node = self.parse_tuple(explicit_parentheses=True)
-            self.stream.expect('rparen')
-        elif token.type == 'lbracket':
+            self.stream.expect("rparen")
+        elif token.type == "lbracket":
             node = self.parse_list()
-        elif token.type == 'lbrace':
+        elif token.type == "lbrace":
             node = self.parse_dict()
         else:
             self.fail("unexpected '%s'" % describe_token(token), token.lineno)
         return node
 
-    def parse_tuple(self, simplified=False, with_condexpr=True,
-                    extra_end_rules=None, explicit_parentheses=False):
+    def parse_tuple(
+        self,
+        simplified=False,
+        with_condexpr=True,
+        extra_end_rules=None,
+        explicit_parentheses=False,
+    ):
         """Works like `parse_expression` but if multiple expressions are
         delimited by a comma a :class:`~jinja2.nodes.Tuple` node is created.
         This method could also return a regular expression instead of a tuple
@@ -615,11 +644,11 @@ class Parser(object):
         is_tuple = False
         while 1:
             if args:
-                self.stream.expect('comma')
+                self.stream.expect("comma")
             if self.is_tuple_end(extra_end_rules):
                 break
             args.append(parse())
-            if self.stream.current.type == 'comma':
+            if self.stream.current.type == "comma":
                 is_tuple = True
             else:
                 break
@@ -634,46 +663,48 @@ class Parser(object):
             # nothing) in the spot of an expression would be an empty
             # tuple.
             if not explicit_parentheses:
-                self.fail('Expected an expression, got \'%s\'' %
-                          describe_token(self.stream.current))
+                self.fail(
+                    "Expected an expression, got '%s'"
+                    % describe_token(self.stream.current)
+                )
 
-        return nodes.Tuple(args, 'load', lineno=lineno)
+        return nodes.Tuple(args, "load", lineno=lineno)
 
     def parse_list(self):
-        token = self.stream.expect('lbracket')
+        token = self.stream.expect("lbracket")
         items = []
-        while self.stream.current.type != 'rbracket':
+        while self.stream.current.type != "rbracket":
             if items:
-                self.stream.expect('comma')
-            if self.stream.current.type == 'rbracket':
+                self.stream.expect("comma")
+            if self.stream.current.type == "rbracket":
                 break
             items.append(self.parse_expression())
-        self.stream.expect('rbracket')
+        self.stream.expect("rbracket")
         return nodes.List(items, lineno=token.lineno)
 
     def parse_dict(self):
-        token = self.stream.expect('lbrace')
+        token = self.stream.expect("lbrace")
         items = []
-        while self.stream.current.type != 'rbrace':
+        while self.stream.current.type != "rbrace":
             if items:
-                self.stream.expect('comma')
-            if self.stream.current.type == 'rbrace':
+                self.stream.expect("comma")
+            if self.stream.current.type == "rbrace":
                 break
             key = self.parse_expression()
-            self.stream.expect('colon')
+            self.stream.expect("colon")
             value = self.parse_expression()
             items.append(nodes.Pair(key, value, lineno=key.lineno))
-        self.stream.expect('rbrace')
+        self.stream.expect("rbrace")
         return nodes.Dict(items, lineno=token.lineno)
 
     def parse_postfix(self, node):
         while 1:
             token_type = self.stream.current.type
-            if token_type == 'dot' or token_type == 'lbracket':
+            if token_type == "dot" or token_type == "lbracket":
                 node = self.parse_subscript(node)
             # calls are valid both after postfix expressions (getattr
             # and getitem) as well as filters and tests
-            elif token_type == 'lparen':
+            elif token_type == "lparen":
                 node = self.parse_call(node)
             else:
                 break
@@ -682,13 +713,13 @@ class Parser(object):
     def parse_filter_expr(self, node):
         while 1:
             token_type = self.stream.current.type
-            if token_type == 'pipe':
+            if token_type == "pipe":
                 node = self.parse_filter(node)
-            elif token_type == 'name' and self.stream.current.value == 'is':
+            elif token_type == "name" and self.stream.current.value == "is":
                 node = self.parse_test(node)
             # calls are valid both after postfix expressions (getattr
             # and getitem) as well as filters and tests
-            elif token_type == 'lparen':
+            elif token_type == "lparen":
                 node = self.parse_call(node)
             else:
                 break
@@ -696,53 +727,54 @@ class Parser(object):
 
     def parse_subscript(self, node):
         token = next(self.stream)
-        if token.type == 'dot':
+        if token.type == "dot":
             attr_token = self.stream.current
             next(self.stream)
-            if attr_token.type == 'name':
-                return nodes.Getattr(node, attr_token.value, 'load',
-                                     lineno=token.lineno)
-            elif attr_token.type != 'integer':
-                self.fail('expected name or number', attr_token.lineno)
+            if attr_token.type == "name":
+                return nodes.Getattr(
+                    node, attr_token.value, "load", lineno=token.lineno
+                )
+            elif attr_token.type != "integer":
+                self.fail("expected name or number", attr_token.lineno)
             arg = nodes.Const(attr_token.value, lineno=attr_token.lineno)
-            return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
-        if token.type == 'lbracket':
+            return nodes.Getitem(node, arg, "load", lineno=token.lineno)
+        if token.type == "lbracket":
             args = []
-            while self.stream.current.type != 'rbracket':
+            while self.stream.current.type != "rbracket":
                 if args:
-                    self.stream.expect('comma')
+                    self.stream.expect("comma")
                 args.append(self.parse_subscribed())
-            self.stream.expect('rbracket')
+            self.stream.expect("rbracket")
             if len(args) == 1:
                 arg = args[0]
             else:
-                arg = nodes.Tuple(args, 'load', lineno=token.lineno)
-            return nodes.Getitem(node, arg, 'load', lineno=token.lineno)
-        self.fail('expected subscript expression', token.lineno)
+                arg = nodes.Tuple(args, "load", lineno=token.lineno)
+            return nodes.Getitem(node, arg, "load", lineno=token.lineno)
+        self.fail("expected subscript expression", token.lineno)
 
     def parse_subscribed(self):
         lineno = self.stream.current.lineno
 
-        if self.stream.current.type == 'colon':
+        if self.stream.current.type == "colon":
             next(self.stream)
             args = [None]
         else:
             node = self.parse_expression()
-            if self.stream.current.type != 'colon':
+            if self.stream.current.type != "colon":
                 return node
             next(self.stream)
             args = [node]
 
-        if self.stream.current.type == 'colon':
+        if self.stream.current.type == "colon":
             args.append(None)
-        elif self.stream.current.type not in ('rbracket', 'comma'):
+        elif self.stream.current.type not in ("rbracket", "comma"):
             args.append(self.parse_expression())
         else:
             args.append(None)
 
-        if self.stream.current.type == 'colon':
+        if self.stream.current.type == "colon":
             next(self.stream)
-            if self.stream.current.type not in ('rbracket', 'comma'):
+            if self.stream.current.type not in ("rbracket", "comma"):
                 args.append(self.parse_expression())
             else:
                 args.append(None)
@@ -752,7 +784,7 @@ class Parser(object):
         return nodes.Slice(lineno=lineno, *args)
 
     def parse_call(self, node):
-        token = self.stream.expect('lparen')
+        token = self.stream.expect("lparen")
         args = []
         kwargs = []
         dyn_args = dyn_kwargs = None
@@ -760,95 +792,100 @@ class Parser(object):
 
         def ensure(expr):
             if not expr:
-                self.fail('invalid syntax for function call expression',
-                          token.lineno)
+                self.fail("invalid syntax for function call expression", token.lineno)
 
-        while self.stream.current.type != 'rparen':
+        while self.stream.current.type != "rparen":
             if require_comma:
-                self.stream.expect('comma')
+                self.stream.expect("comma")
                 # support for trailing comma
-                if self.stream.current.type == 'rparen':
+                if self.stream.current.type == "rparen":
                     break
-            if self.stream.current.type == 'mul':
+            if self.stream.current.type == "mul":
                 ensure(dyn_args is None and dyn_kwargs is None)
                 next(self.stream)
                 dyn_args = self.parse_expression()
-            elif self.stream.current.type == 'pow':
+            elif self.stream.current.type == "pow":
                 ensure(dyn_kwargs is None)
                 next(self.stream)
                 dyn_kwargs = self.parse_expression()
             else:
-                if self.stream.current.type == 'name' and \
-                   self.stream.look().type == 'assign':
+                if (
+                    self.stream.current.type == "name"
+                    and self.stream.look().type == "assign"
+                ):
                     # Parsing a kwarg
                     ensure(dyn_kwargs is None)
                     key = self.stream.current.value
                     self.stream.skip(2)
                     value = self.parse_expression()
-                    kwargs.append(nodes.Keyword(key, value,
-                                                lineno=value.lineno))
+                    kwargs.append(nodes.Keyword(key, value, lineno=value.lineno))
                 else:
                     # Parsing an arg
                     ensure(dyn_args is None and dyn_kwargs is None and not kwargs)
                     args.append(self.parse_expression())
 
             require_comma = True
-        self.stream.expect('rparen')
+        self.stream.expect("rparen")
 
         if node is None:
             return args, kwargs, dyn_args, dyn_kwargs
-        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs,
-                          lineno=token.lineno)
+        return nodes.Call(node, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno)
 
     def parse_filter(self, node, start_inline=False):
-        while self.stream.current.type == 'pipe' or start_inline:
+        while self.stream.current.type == "pipe" or start_inline:
             if not start_inline:
                 next(self.stream)
-            token = self.stream.expect('name')
+            token = self.stream.expect("name")
             name = token.value
-            while self.stream.current.type == 'dot':
+            while self.stream.current.type == "dot":
                 next(self.stream)
-                name += '.' + self.stream.expect('name').value
-            if self.stream.current.type == 'lparen':
+                name += "." + self.stream.expect("name").value
+            if self.stream.current.type == "lparen":
                 args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
             else:
                 args = []
                 kwargs = []
                 dyn_args = dyn_kwargs = None
-            node = nodes.Filter(node, name, args, kwargs, dyn_args,
-                                dyn_kwargs, lineno=token.lineno)
+            node = nodes.Filter(
+                node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
+            )
             start_inline = False
         return node
 
     def parse_test(self, node):
         token = next(self.stream)
-        if self.stream.current.test('name:not'):
+        if self.stream.current.test("name:not"):
             next(self.stream)
             negated = True
         else:
             negated = False
-        name = self.stream.expect('name').value
-        while self.stream.current.type == 'dot':
+        name = self.stream.expect("name").value
+        while self.stream.current.type == "dot":
             next(self.stream)
-            name += '.' + self.stream.expect('name').value
+            name += "." + self.stream.expect("name").value
         dyn_args = dyn_kwargs = None
         kwargs = []
-        if self.stream.current.type == 'lparen':
+        if self.stream.current.type == "lparen":
             args, kwargs, dyn_args, dyn_kwargs = self.parse_call(None)
-        elif (self.stream.current.type in ('name', 'string', 'integer',
-                                           'float', 'lparen', 'lbracket',
-                                           'lbrace') and not
-              self.stream.current.test_any('name:else', 'name:or',
-                                           'name:and')):
-            if self.stream.current.test('name:is'):
-                self.fail('You cannot chain multiple tests with is')
+        elif self.stream.current.type in (
+            "name",
+            "string",
+            "integer",
+            "float",
+            "lparen",
+            "lbracket",
+            "lbrace",
+        ) and not self.stream.current.test_any("name:else", "name:or", "name:and"):
+            if self.stream.current.test("name:is"):
+                self.fail("You cannot chain multiple tests with is")
             arg_node = self.parse_primary()
             arg_node = self.parse_postfix(arg_node)
             args = [arg_node]
         else:
             args = []
-        node = nodes.Test(node, name, args, kwargs, dyn_args,
-                          dyn_kwargs, lineno=token.lineno)
+        node = nodes.Test(
+            node, name, args, kwargs, dyn_args, dyn_kwargs, lineno=token.lineno
+        )
         if negated:
             node = nodes.Not(node, lineno=token.lineno)
         return node
@@ -870,29 +907,29 @@ class Parser(object):
         try:
             while self.stream:
                 token = self.stream.current
-                if token.type == 'data':
+                if token.type == "data":
                     if token.value:
-                        add_data(nodes.TemplateData(token.value,
-                                                    lineno=token.lineno))
+                        add_data(nodes.TemplateData(token.value, lineno=token.lineno))
                     next(self.stream)
-                elif token.type == 'variable_begin':
+                elif token.type == "variable_begin":
                     next(self.stream)
                     add_data(self.parse_tuple(with_condexpr=True))
-                    self.stream.expect('variable_end')
-                elif token.type == 'block_begin':
+                    self.stream.expect("variable_end")
+                elif token.type == "block_begin":
                     flush_data()
                     next(self.stream)
-                    if end_tokens is not None and \
-                       self.stream.current.test_any(*end_tokens):
+                    if end_tokens is not None and self.stream.current.test_any(
+                        *end_tokens
+                    ):
                         return body
                     rv = self.parse_statement()
                     if isinstance(rv, list):
                         body.extend(rv)
                     else:
                         body.append(rv)
-                    self.stream.expect('block_end')
+                    self.stream.expect("block_end")
                 else:
-                    raise AssertionError('internal parsing error')
+                    raise AssertionError("internal parsing error")
 
             flush_data()
         finally:
index 7ee9927adb5c236b16f4d2f1dbb2c1652e0262c4..9f4f224d08dbb95f111ffd9268418552b9bd3b29 100644 (file)
@@ -36,10 +36,23 @@ from .utils import object_type_repr
 from .utils import soft_unicode
 
 # these variables are exported to the template runtime
-__all__ = ['LoopContext', 'TemplateReference', 'Macro', 'Markup',
-           'TemplateRuntimeError', 'missing', 'concat', 'escape',
-           'markup_join', 'unicode_join', 'to_string', 'identity',
-           'TemplateNotFound', 'Namespace', 'Undefined']
+__all__ = [
+    "LoopContext",
+    "TemplateReference",
+    "Macro",
+    "Markup",
+    "TemplateRuntimeError",
+    "missing",
+    "concat",
+    "escape",
+    "markup_join",
+    "unicode_join",
+    "to_string",
+    "identity",
+    "TemplateNotFound",
+    "Namespace",
+    "Undefined",
+]
 
 #: the name of the function that is used to convert something into
 #: a string.  We can just use the text type here.
@@ -58,8 +71,8 @@ def markup_join(seq):
     iterator = imap(soft_unicode, seq)
     for arg in iterator:
         buf.append(arg)
-        if hasattr(arg, '__html__'):
-            return Markup(u'').join(chain(buf, iterator))
+        if hasattr(arg, "__html__"):
+            return Markup(u"").join(chain(buf, iterator))
     return concat(buf)
 
 
@@ -68,8 +81,15 @@ def unicode_join(seq):
     return concat(imap(text_type, seq))
 
 
-def new_context(environment, template_name, blocks, vars=None,
-                shared=None, globals=None, locals=None):
+def new_context(
+    environment,
+    template_name,
+    blocks,
+    vars=None,
+    shared=None,
+    globals=None,
+    locals=None,
+):
     """Internal helper for context creation."""
     if vars is None:
         vars = {}
@@ -85,8 +105,7 @@ def new_context(environment, template_name, blocks, vars=None,
         for key, value in iteritems(locals):
             if value is not missing:
                 parent[key] = value
-    return environment.context_class(environment, parent, template_name,
-                                     blocks)
+    return environment.context_class(environment, parent, template_name, blocks)
 
 
 class TemplateReference(object):
@@ -100,18 +119,14 @@ class TemplateReference(object):
         return BlockReference(name, self.__context, blocks, 0)
 
     def __repr__(self):
-        return '<%s %r>' % (
-            self.__class__.__name__,
-            self.__context.name
-        )
+        return "<%s %r>" % (self.__class__.__name__, self.__context.name)
 
 
 def _get_func(x):
-    return getattr(x, '__func__', x)
+    return getattr(x, "__func__", x)
 
 
 class ContextMeta(type):
-
     def __new__(cls, name, bases, d):
         rv = type.__new__(cls, name, bases, d)
         if bases == ():
@@ -124,11 +139,15 @@ class ContextMeta(type):
 
         # If we have a changed resolve but no changed default or missing
         # resolve we invert the call logic.
-        if resolve is not default_resolve and \
-           resolve_or_missing is default_resolve_or_missing:
+        if (
+            resolve is not default_resolve
+            and resolve_or_missing is default_resolve_or_missing
+        ):
             rv._legacy_resolve_mode = True
-        elif resolve is default_resolve and \
-             resolve_or_missing is default_resolve_or_missing:
+        elif (
+            resolve is default_resolve
+            and resolve_or_missing is default_resolve_or_missing
+        ):
             rv._fast_resolve_mode = True
 
         return rv
@@ -161,6 +180,7 @@ class Context(with_metaclass(ContextMeta)):
     method that doesn't fail with a `KeyError` but returns an
     :class:`Undefined` object for missing variables.
     """
+
     # XXX: we want to eventually make this be a deprecation warning and
     # remove it.
     _legacy_resolve_mode = False
@@ -191,9 +211,9 @@ class Context(with_metaclass(ContextMeta)):
             index = blocks.index(current) + 1
             blocks[index]
         except LookupError:
-            return self.environment.undefined('there is no parent block '
-                                              'called %r.' % name,
-                                              name='super')
+            return self.environment.undefined(
+                "there is no parent block called %r." % name, name="super"
+            )
         return BlockReference(name, self, blocks, index)
 
     def get(self, key, default=None):
@@ -254,36 +274,41 @@ class Context(with_metaclass(ContextMeta)):
             __traceback_hide__ = True  # noqa
 
         # Allow callable classes to take a context
-        if hasattr(__obj, '__call__'):
+        if hasattr(__obj, "__call__"):
             fn = __obj.__call__
-            for fn_type in ('contextfunction',
-                            'evalcontextfunction',
-                            'environmentfunction'):
+            for fn_type in (
+                "contextfunction",
+                "evalcontextfunction",
+                "environmentfunction",
+            ):
                 if hasattr(fn, fn_type):
                     __obj = fn
                     break
 
         if callable(__obj):
-            if getattr(__obj, 'contextfunction', 0):
+            if getattr(__obj, "contextfunction", 0):
                 args = (__self,) + args
-            elif getattr(__obj, 'evalcontextfunction', 0):
+            elif getattr(__obj, "evalcontextfunction", 0):
                 args = (__self.eval_ctx,) + args
-            elif getattr(__obj, 'environmentfunction', 0):
+            elif getattr(__obj, "environmentfunction", 0):
                 args = (__self.environment,) + args
         try:
             return __obj(*args, **kwargs)
         except StopIteration:
-            return __self.environment.undefined('value was undefined because '
-                                                'a callable raised a '
-                                                'StopIteration exception')
+            return __self.environment.undefined(
+                "value was undefined because "
+                "a callable raised a "
+                "StopIteration exception"
+            )
 
     def derived(self, locals=None):
         """Internal helper function to create a derived context.  This is
         used in situations where the system needs a new context in the same
         template that is independent.
         """
-        context = new_context(self.environment, self.name, {},
-                              self.get_all(), True, None, locals)
+        context = new_context(
+            self.environment, self.name, {}, self.get_all(), True, None, locals
+        )
         context.eval_ctx = self.eval_ctx
         context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
         return context
@@ -294,15 +319,15 @@ class Context(with_metaclass(ContextMeta)):
         proxy.__name__ = meth
         return proxy
 
-    keys = _all('keys')
-    values = _all('values')
-    items = _all('items')
+    keys = _all("keys")
+    values = _all("values")
+    items = _all("items")
 
     # not available on python 3
     if PY2:
-        iterkeys = _all('iterkeys')
-        itervalues = _all('itervalues')
-        iteritems = _all('iteritems')
+        iterkeys = _all("iterkeys")
+        itervalues = _all("itervalues")
+        iteritems = _all("iteritems")
     del _all
 
     def __contains__(self, name):
@@ -318,10 +343,10 @@ class Context(with_metaclass(ContextMeta)):
         return item
 
     def __repr__(self):
-        return '<%s %s of %r>' % (
+        return "<%s %s of %r>" % (
             self.__class__.__name__,
             repr(self.get_all()),
-            self.name
+            self.name,
         )
 
 
@@ -341,11 +366,10 @@ class BlockReference(object):
     def super(self):
         """Super the block."""
         if self._depth + 1 >= len(self._stack):
-            return self._context.environment. \
-                undefined('there is no parent block called %r.' %
-                          self.name, name='super')
-        return BlockReference(self.name, self._context, self._stack,
-                              self._depth + 1)
+            return self._context.environment.undefined(
+                "there is no parent block called %r." % self.name, name="super"
+            )
+        return BlockReference(self.name, self._context, self._stack, self._depth + 1)
 
     @internalcode
     def __call__(self):
@@ -538,8 +562,7 @@ class LoopContext:
         """
         if self._recurse is None:
             raise TypeError(
-                "The loop must have the 'recursive' marker to be"
-                " called recursively."
+                "The loop must have the 'recursive' marker to be called recursively."
             )
 
         return self._recurse(iterable, self._recurse, depth=self.depth)
@@ -551,9 +574,17 @@ class LoopContext:
 class Macro(object):
     """Wraps a macro function."""
 
-    def __init__(self, environment, func, name, arguments,
-                 catch_kwargs, catch_varargs, caller,
-                 default_autoescape=None):
+    def __init__(
+        self,
+        environment,
+        func,
+        name,
+        arguments,
+        catch_kwargs,
+        catch_varargs,
+        caller,
+        default_autoescape=None,
+    ):
         self._environment = environment
         self._func = func
         self._argument_count = len(arguments)
@@ -562,7 +593,7 @@ class Macro(object):
         self.catch_kwargs = catch_kwargs
         self.catch_varargs = catch_varargs
         self.caller = caller
-        self.explicit_caller = 'caller' in arguments
+        self.explicit_caller = "caller" in arguments
         if default_autoescape is None:
             default_autoescape = environment.autoescape
         self._default_autoescape = default_autoescape
@@ -593,7 +624,7 @@ class Macro(object):
             autoescape = self._default_autoescape
 
         # try to consume the positional arguments
-        arguments = list(args[:self._argument_count])
+        arguments = list(args[: self._argument_count])
         off = len(arguments)
 
         # For information why this is necessary refer to the handling
@@ -604,12 +635,12 @@ class Macro(object):
         # arguments expected we start filling in keyword arguments
         # and defaults.
         if off != self._argument_count:
-            for idx, name in enumerate(self.arguments[len(arguments):]):
+            for idx, name in enumerate(self.arguments[len(arguments) :]):
                 try:
                     value = kwargs.pop(name)
                 except KeyError:
                     value = missing
-                if name == 'caller':
+                if name == "caller":
                     found_caller = True
                 arguments.append(value)
         else:
@@ -619,26 +650,31 @@ class Macro(object):
         # if not also changed in the compiler's `function_scoping` method.
         # the order is caller, keyword arguments, positional arguments!
         if self.caller and not found_caller:
-            caller = kwargs.pop('caller', None)
+            caller = kwargs.pop("caller", None)
             if caller is None:
-                caller = self._environment.undefined('No caller defined',
-                                                     name='caller')
+                caller = self._environment.undefined("No caller defined", name="caller")
             arguments.append(caller)
 
         if self.catch_kwargs:
             arguments.append(kwargs)
         elif kwargs:
-            if 'caller' in kwargs:
-                raise TypeError('macro %r was invoked with two values for '
-                                'the special caller argument.  This is '
-                                'most likely a bug.' % self.name)
-            raise TypeError('macro %r takes no keyword argument %r' %
-                            (self.name, next(iter(kwargs))))
+            if "caller" in kwargs:
+                raise TypeError(
+                    "macro %r was invoked with two values for "
+                    "the special caller argument.  This is "
+                    "most likely a bug." % self.name
+                )
+            raise TypeError(
+                "macro %r takes no keyword argument %r"
+                % (self.name, next(iter(kwargs)))
+            )
         if self.catch_varargs:
-            arguments.append(args[self._argument_count:])
+            arguments.append(args[self._argument_count :])
         elif len(args) > self._argument_count:
-            raise TypeError('macro %r takes not more than %d argument(s)' %
-                            (self.name, len(self.arguments)))
+            raise TypeError(
+                "macro %r takes not more than %d argument(s)"
+                % (self.name, len(self.arguments))
+            )
 
         return self._invoke(arguments, autoescape)
 
@@ -650,9 +686,9 @@ class Macro(object):
         return rv
 
     def __repr__(self):
-        return '<%s %s>' % (
+        return "<%s %s>" % (
             self.__class__.__name__,
-            self.name is None and 'anonymous' or repr(self.name)
+            self.name is None and "anonymous" or repr(self.name),
         )
 
 
@@ -671,8 +707,13 @@ class Undefined(object):
       ...
     jinja2.exceptions.UndefinedError: 'foo' is undefined
     """
-    __slots__ = ('_undefined_hint', '_undefined_obj', '_undefined_name',
-                 '_undefined_exception')
+
+    __slots__ = (
+        "_undefined_hint",
+        "_undefined_obj",
+        "_undefined_name",
+        "_undefined_exception",
+    )
 
     def __init__(self, hint=None, obj=missing, name=None, exc=UndefinedError):
         self._undefined_hint = hint
@@ -689,17 +730,17 @@ class Undefined(object):
             return self._undefined_hint
 
         if self._undefined_obj is missing:
-            return '%r is undefined' % self._undefined_name
+            return "%r is undefined" % self._undefined_name
 
         if not isinstance(self._undefined_name, string_types):
-            return '%s has no element %r' % (
+            return "%s has no element %r" % (
                 object_type_repr(self._undefined_obj),
-                self._undefined_name
+                self._undefined_name,
             )
 
-        return '%r has no attribute %r' % (
+        return "%r has no attribute %r" % (
             object_type_repr(self._undefined_obj),
-            self._undefined_name
+            self._undefined_name,
         )
 
     @internalcode
@@ -711,16 +752,55 @@ class Undefined(object):
 
     @internalcode
     def __getattr__(self, name):
-        if name[:2] == '__':
+        if name[:2] == "__":
             raise AttributeError(name)
         return self._fail_with_undefined_error()
 
-    __add__ = __radd__ = __mul__ = __rmul__ = __div__ = __rdiv__ = \
-        __truediv__ = __rtruediv__ = __floordiv__ = __rfloordiv__ = \
-        __mod__ = __rmod__ = __pos__ = __neg__ = __call__ = \
-        __getitem__ = __lt__ = __le__ = __gt__ = __ge__ = __int__ = \
-        __float__ = __complex__ = __pow__ = __rpow__ = __sub__ = \
-        __rsub__ = _fail_with_undefined_error
+    __add__ = (
+        __radd__
+    ) = (
+        __mul__
+    ) = (
+        __rmul__
+    ) = (
+        __div__
+    ) = (
+        __rdiv__
+    ) = (
+        __truediv__
+    ) = (
+        __rtruediv__
+    ) = (
+        __floordiv__
+    ) = (
+        __rfloordiv__
+    ) = (
+        __mod__
+    ) = (
+        __rmod__
+    ) = (
+        __pos__
+    ) = (
+        __neg__
+    ) = (
+        __call__
+    ) = (
+        __getitem__
+    ) = (
+        __lt__
+    ) = (
+        __le__
+    ) = (
+        __gt__
+    ) = (
+        __ge__
+    ) = (
+        __int__
+    ) = (
+        __float__
+    ) = (
+        __complex__
+    ) = __pow__ = __rpow__ = __sub__ = __rsub__ = _fail_with_undefined_error
 
     def __eq__(self, other):
         return type(self) is type(other)
@@ -732,7 +812,7 @@ class Undefined(object):
         return id(type(self))
 
     def __str__(self):
-        return u''
+        return u""
 
     def __len__(self):
         return 0
@@ -743,10 +823,11 @@ class Undefined(object):
 
     def __nonzero__(self):
         return False
+
     __bool__ = __nonzero__
 
     def __repr__(self):
-        return 'Undefined'
+        return "Undefined"
 
 
 def make_logging_undefined(logger=None, base=None):
@@ -771,6 +852,7 @@ def make_logging_undefined(logger=None, base=None):
     """
     if logger is None:
         import logging
+
         logger = logging.getLogger(__name__)
         logger.addHandler(logging.StreamHandler(sys.stderr))
     if base is None:
@@ -779,26 +861,27 @@ def make_logging_undefined(logger=None, base=None):
     def _log_message(undef):
         if undef._undefined_hint is None:
             if undef._undefined_obj is missing:
-                hint = '%s is undefined' % undef._undefined_name
+                hint = "%s is undefined" % undef._undefined_name
             elif not isinstance(undef._undefined_name, string_types):
-                hint = '%s has no element %s' % (
+                hint = "%s has no element %s" % (
                     object_type_repr(undef._undefined_obj),
-                    undef._undefined_name)
+                    undef._undefined_name,
+                )
             else:
-                hint = '%s has no attribute %s' % (
+                hint = "%s has no attribute %s" % (
                     object_type_repr(undef._undefined_obj),
-                    undef._undefined_name)
+                    undef._undefined_name,
+                )
         else:
             hint = undef._undefined_hint
-        logger.warning('Template variable warning: %s', hint)
+        logger.warning("Template variable warning: %s", hint)
 
     class LoggingUndefined(base):
-
         def _fail_with_undefined_error(self, *args, **kwargs):
             try:
                 return base._fail_with_undefined_error(self, *args, **kwargs)
             except self._undefined_exception as e:
-                logger.error('Template variable error: %s', str(e))
+                logger.error("Template variable error: %s", str(e))
                 raise e
 
         def __str__(self):
@@ -812,6 +895,7 @@ def make_logging_undefined(logger=None, base=None):
             return rv
 
         if PY2:
+
             def __nonzero__(self):
                 rv = base.__nonzero__(self)
                 _log_message(self)
@@ -821,7 +905,9 @@ def make_logging_undefined(logger=None, base=None):
                 rv = base.__unicode__(self)
                 _log_message(self)
                 return rv
+
         else:
+
             def __bool__(self):
                 rv = base.__bool__(self)
                 _log_message(self)
@@ -848,6 +934,7 @@ class ChainableUndefined(Undefined):
 
     .. versionadded:: 2.11.0
     """
+
     __slots__ = ()
 
     def __html__(self):
@@ -873,17 +960,18 @@ class DebugUndefined(Undefined):
       ...
     jinja2.exceptions.UndefinedError: 'foo' is undefined
     """
+
     __slots__ = ()
 
     def __str__(self):
         if self._undefined_hint is None:
             if self._undefined_obj is missing:
-                return u'{{ %s }}' % self._undefined_name
-            return '{{ no such element: %s[%r] }}' % (
+                return u"{{ %s }}" % self._undefined_name
+            return "{{ no such element: %s[%r] }}" % (
                 object_type_repr(self._undefined_obj),
-                self._undefined_name
+                self._undefined_name,
             )
-        return u'{{ undefined value printed: %s }}' % self._undefined_hint
+        return u"{{ undefined value printed: %s }}" % self._undefined_hint
 
 
 @implements_to_string
@@ -906,13 +994,22 @@ class StrictUndefined(Undefined):
       ...
     jinja2.exceptions.UndefinedError: 'foo' is undefined
     """
+
     __slots__ = ()
-    __iter__ = __str__ = __len__ = __nonzero__ = __eq__ = \
-        __ne__ = __bool__ = __hash__ = \
-        Undefined._fail_with_undefined_error
+    __iter__ = (
+        __str__
+    ) = (
+        __len__
+    ) = (
+        __nonzero__
+    ) = __eq__ = __ne__ = __bool__ = __hash__ = Undefined._fail_with_undefined_error
 
 
 # remove remaining slots attributes, after the metaclass did the magic they
 # are unneeded and irritating as they contain wrong data for the subclasses.
-del Undefined.__slots__, ChainableUndefined.__slots__, \
-    DebugUndefined.__slots__, StrictUndefined.__slots__
+del (
+    Undefined.__slots__,
+    ChainableUndefined.__slots__,
+    DebugUndefined.__slots__,
+    StrictUndefined.__slots__,
+)
index a614c272443b498b2ff1cf6895b6953ac72eaabc..ad87997c8ec178140224c2e913f403c1b810662d 100644 (file)
@@ -31,8 +31,9 @@ MAX_RANGE = 100000
 
 #: attributes of function objects that are considered unsafe.
 if PY2:
-    UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
-                                      'func_defaults', 'func_globals'])
+    UNSAFE_FUNCTION_ATTRIBUTES = set(
+        ["func_closure", "func_code", "func_dict", "func_defaults", "func_globals"]
+    )
 else:
     # On versions > python 2 the special attributes on functions are gone,
     # but they remain on methods and generators for whatever reason.
@@ -40,22 +41,23 @@ else:
 
 
 #: unsafe method attributes.  function attributes are unsafe for methods too
-UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
+UNSAFE_METHOD_ATTRIBUTES = set(["im_class", "im_func", "im_self"])
 
 #: unsafe generator attributes.
-UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
+UNSAFE_GENERATOR_ATTRIBUTES = set(["gi_frame", "gi_code"])
 
 #: unsafe attributes on coroutines
-UNSAFE_COROUTINE_ATTRIBUTES = set(['cr_frame', 'cr_code'])
+UNSAFE_COROUTINE_ATTRIBUTES = set(["cr_frame", "cr_code"])
 
 #: unsafe attributes on async generators
-UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set(['ag_code', 'ag_frame'])
+UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set(["ag_code", "ag_frame"])
 
 import warnings
 
 # make sure we don't warn in python 2.6 about stuff we don't care about
-warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
-                        module='jinja2.sandbox')
+warnings.filterwarnings(
+    "ignore", "the sets module", DeprecationWarning, module="jinja2.sandbox"
+)
 
 from collections import deque
 
@@ -68,6 +70,7 @@ _mutable_sequence_types = (list,)
 try:
     from UserDict import UserDict, DictMixin
     from UserList import UserList
+
     _mutable_mapping_types += (UserDict, DictMixin)
     _mutable_set_types += (UserList,)
 except ImportError:
@@ -76,6 +79,7 @@ except ImportError:
 # if sets is still available, register the mutable set from there as well
 try:
     from sets import Set
+
     _mutable_set_types += (Set,)
 except ImportError:
     pass
@@ -87,20 +91,45 @@ _mutable_sequence_types += (abc.MutableSequence,)
 
 
 _mutable_spec = (
-    (_mutable_set_types, frozenset([
-        'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
-        'symmetric_difference_update', 'update'
-    ])),
-    (_mutable_mapping_types, frozenset([
-        'clear', 'pop', 'popitem', 'setdefault', 'update'
-    ])),
-    (_mutable_sequence_types, frozenset([
-        'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
-    ])),
-    (deque, frozenset([
-        'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
-        'popleft', 'remove', 'rotate'
-    ]))
+    (
+        _mutable_set_types,
+        frozenset(
+            [
+                "add",
+                "clear",
+                "difference_update",
+                "discard",
+                "pop",
+                "remove",
+                "symmetric_difference_update",
+                "update",
+            ]
+        ),
+    ),
+    (
+        _mutable_mapping_types,
+        frozenset(["clear", "pop", "popitem", "setdefault", "update"]),
+    ),
+    (
+        _mutable_sequence_types,
+        frozenset(["append", "reverse", "insert", "sort", "extend", "remove"]),
+    ),
+    (
+        deque,
+        frozenset(
+            [
+                "append",
+                "appendleft",
+                "clear",
+                "extend",
+                "extendleft",
+                "pop",
+                "popleft",
+                "remove",
+                "rotate",
+            ]
+        ),
+    ),
 )
 
 
@@ -118,7 +147,7 @@ class _MagicFormatMapping(abc.Mapping):
         self._last_index = 0
 
     def __getitem__(self, key):
-        if key == '':
+        if key == "":
             idx = self._last_index
             self._last_index += 1
             try:
@@ -136,9 +165,9 @@ class _MagicFormatMapping(abc.Mapping):
 
 
 def inspect_format_method(callable):
-    if not isinstance(callable, (types.MethodType,
-                                 types.BuiltinMethodType)) or \
-       callable.__name__ not in ('format', 'format_map'):
+    if not isinstance(
+        callable, (types.MethodType, types.BuiltinMethodType)
+    ) or callable.__name__ not in ("format", "format_map"):
         return None
     obj = callable.__self__
     if isinstance(obj, string_types):
@@ -189,24 +218,25 @@ def is_internal_attribute(obj, attr):
         if attr in UNSAFE_FUNCTION_ATTRIBUTES:
             return True
     elif isinstance(obj, types.MethodType):
-        if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
-           attr in UNSAFE_METHOD_ATTRIBUTES:
+        if attr in UNSAFE_FUNCTION_ATTRIBUTES or attr in UNSAFE_METHOD_ATTRIBUTES:
             return True
     elif isinstance(obj, type):
-        if attr == 'mro':
+        if attr == "mro":
             return True
     elif isinstance(obj, (types.CodeType, types.TracebackType, types.FrameType)):
         return True
     elif isinstance(obj, types.GeneratorType):
         if attr in UNSAFE_GENERATOR_ATTRIBUTES:
             return True
-    elif hasattr(types, 'CoroutineType') and isinstance(obj, types.CoroutineType):
+    elif hasattr(types, "CoroutineType") and isinstance(obj, types.CoroutineType):
         if attr in UNSAFE_COROUTINE_ATTRIBUTES:
             return True
-    elif hasattr(types, 'AsyncGeneratorType') and isinstance(obj, types.AsyncGeneratorType):
+    elif hasattr(types, "AsyncGeneratorType") and isinstance(
+        obj, types.AsyncGeneratorType
+    ):
         if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
             return True
-    return attr.startswith('__')
+    return attr.startswith("__")
 
 
 def modifies_known_mutable(obj, attr):
@@ -247,28 +277,26 @@ class SandboxedEnvironment(Environment):
     raised.  However also other exceptions may occur during the rendering so
     the caller has to ensure that all exceptions are caught.
     """
+
     sandboxed = True
 
     #: default callback table for the binary operators.  A copy of this is
     #: available on each instance of a sandboxed environment as
     #: :attr:`binop_table`
     default_binop_table = {
-        '+':        operator.add,
-        '-':        operator.sub,
-        '*':        operator.mul,
-        '/':        operator.truediv,
-        '//':       operator.floordiv,
-        '**':       operator.pow,
-        '%':        operator.mod
+        "+": operator.add,
+        "-": operator.sub,
+        "*": operator.mul,
+        "/": operator.truediv,
+        "//": operator.floordiv,
+        "**": operator.pow,
+        "%": operator.mod,
     }
 
     #: default callback table for the unary operators.  A copy of this is
     #: available on each instance of a sandboxed environment as
     #: :attr:`unop_table`
-    default_unop_table = {
-        '+':        operator.pos,
-        '-':        operator.neg
-    }
+    default_unop_table = {"+": operator.pos, "-": operator.neg}
 
     #: a set of binary operators that should be intercepted.  Each operator
     #: that is added to this set (empty by default) is delegated to the
@@ -318,10 +346,9 @@ class SandboxedEnvironment(Environment):
         """
         return False
 
-
     def __init__(self, *args, **kwargs):
         Environment.__init__(self, *args, **kwargs)
-        self.globals['range'] = safe_range
+        self.globals["range"] = safe_range
         self.binop_table = self.default_binop_table.copy()
         self.unop_table = self.default_unop_table.copy()
 
@@ -332,7 +359,7 @@ class SandboxedEnvironment(Environment):
         special attributes of internal python objects as returned by the
         :func:`is_internal_attribute` function.
         """
-        return not (attr.startswith('_') or is_internal_attribute(obj, attr))
+        return not (attr.startswith("_") or is_internal_attribute(obj, attr))
 
     def is_safe_callable(self, obj):
         """Check if an object is safely callable.  Per default a function is
@@ -340,8 +367,9 @@ class SandboxedEnvironment(Environment):
         True.  Override this method to alter the behavior, but this won't
         affect the `unsafe` decorator from this module.
         """
-        return not (getattr(obj, 'unsafe_callable', False) or
-                    getattr(obj, 'alters_data', False))
+        return not (
+            getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False)
+        )
 
     def call_binop(self, context, operator, left, right):
         """For intercepted binary operator calls (:meth:`intercepted_binops`)
@@ -401,11 +429,13 @@ class SandboxedEnvironment(Environment):
 
     def unsafe_undefined(self, obj, attribute):
         """Return an undefined object for unsafe attributes."""
-        return self.undefined('access to attribute %r of %r '
-                              'object is unsafe.' % (
-            attribute,
-            obj.__class__.__name__
-        ), name=attribute, obj=obj, exc=SecurityError)
+        return self.undefined(
+            "access to attribute %r of %r "
+            "object is unsafe." % (attribute, obj.__class__.__name__),
+            name=attribute,
+            obj=obj,
+            exc=SecurityError,
+        )
 
     def format_string(self, s, args, kwargs, format_func=None):
         """If a format call is detected, then this is routed through this
@@ -416,10 +446,10 @@ class SandboxedEnvironment(Environment):
         else:
             formatter = SandboxedFormatter(self)
 
-        if format_func is not None and format_func.__name__ == 'format_map':
+        if format_func is not None and format_func.__name__ == "format_map":
             if len(args) != 1 or kwargs:
                 raise TypeError(
-                    'format_map() takes exactly one argument %d given'
+                    "format_map() takes exactly one argument %d given"
                     % (len(args) + (kwargs is not None))
                 )
 
@@ -439,7 +469,7 @@ class SandboxedEnvironment(Environment):
         # the double prefixes are to avoid double keyword argument
         # errors when proxying the call.
         if not __self.is_safe_callable(__obj):
-            raise SecurityError('%r is not safely callable' % (__obj,))
+            raise SecurityError("%r is not safely callable" % (__obj,))
         return __context.call(__obj, *args, **kwargs)
 
 
@@ -459,12 +489,12 @@ class ImmutableSandboxedEnvironment(SandboxedEnvironment):
 try:
     from _string import formatter_field_name_split
 except ImportError:
+
     def formatter_field_name_split(field_name):
         return field_name._formatter_field_name_split()
 
 
 class SandboxedFormatterMixin(object):
-
     def __init__(self, env):
         self._env = env
 
@@ -478,14 +508,14 @@ class SandboxedFormatterMixin(object):
                 obj = self._env.getitem(obj, i)
         return obj, first
 
-class SandboxedFormatter(SandboxedFormatterMixin, Formatter):
 
+class SandboxedFormatter(SandboxedFormatterMixin, Formatter):
     def __init__(self, env):
         SandboxedFormatterMixin.__init__(self, env)
         Formatter.__init__(self)
 
-class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):
 
+class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):
     def __init__(self, env, escape):
         SandboxedFormatterMixin.__init__(self, env)
         EscapeFormatter.__init__(self, escape)
index de0f10595b2c5c89d3013632d01bbade8bc30fa1..3eea947907fcd4b5be49ef3022fd1b79c181555c 100644 (file)
@@ -18,7 +18,7 @@ from ._compat import string_types
 from ._compat import text_type
 from .runtime import Undefined
 
-number_re = re.compile(r'^-?\d+(\.\d+)?$')
+number_re = re.compile(r"^-?\d+(\.\d+)?$")
 regex_type = type(number_re)
 test_callable = callable
 
@@ -171,7 +171,7 @@ def test_iterable(value):
 
 def test_escaped(value):
     """Check if the value is escaped."""
-    return hasattr(value, '__html__')
+    return hasattr(value, "__html__")
 
 
 def test_in(value, seq):
@@ -183,41 +183,41 @@ def test_in(value, seq):
 
 
 TESTS = {
-    'odd':              test_odd,
-    'even':             test_even,
-    'divisibleby':      test_divisibleby,
-    'defined':          test_defined,
-    'undefined':        test_undefined,
-    'none':             test_none,
-    'boolean':          test_boolean,
-    'false':            test_false,
-    'true':             test_true,
-    'integer':          test_integer,
-    'float':            test_float,
-    'lower':            test_lower,
-    'upper':            test_upper,
-    'string':           test_string,
-    'mapping':          test_mapping,
-    'number':           test_number,
-    'sequence':         test_sequence,
-    'iterable':         test_iterable,
-    'callable':         test_callable,
-    'sameas':           test_sameas,
-    'escaped':          test_escaped,
-    'in':               test_in,
-    '==':               operator.eq,
-    'eq':               operator.eq,
-    'equalto':          operator.eq,
-    '!=':               operator.ne,
-    'ne':               operator.ne,
-    '>':                operator.gt,
-    'gt':               operator.gt,
-    'greaterthan':      operator.gt,
-    'ge':               operator.ge,
-    '>=':               operator.ge,
-    '<':                operator.lt,
-    'lt':               operator.lt,
-    'lessthan':         operator.lt,
-    '<=':               operator.le,
-    'le':               operator.le,
+    "odd": test_odd,
+    "even": test_even,
+    "divisibleby": test_divisibleby,
+    "defined": test_defined,
+    "undefined": test_undefined,
+    "none": test_none,
+    "boolean": test_boolean,
+    "false": test_false,
+    "true": test_true,
+    "integer": test_integer,
+    "float": test_float,
+    "lower": test_lower,
+    "upper": test_upper,
+    "string": test_string,
+    "mapping": test_mapping,
+    "number": test_number,
+    "sequence": test_sequence,
+    "iterable": test_iterable,
+    "callable": test_callable,
+    "sameas": test_sameas,
+    "escaped": test_escaped,
+    "in": test_in,
+    "==": operator.eq,
+    "eq": operator.eq,
+    "equalto": operator.eq,
+    "!=": operator.ne,
+    "ne": operator.ne,
+    ">": operator.gt,
+    "gt": operator.gt,
+    "greaterthan": operator.gt,
+    "ge": operator.ge,
+    ">=": operator.ge,
+    "<": operator.lt,
+    "lt": operator.lt,
+    "lessthan": operator.lt,
+    "<=": operator.le,
+    "le": operator.le,
 }
index de36eefa42f82671946308574ed484b92ecfdc74..c051f30b89693839d13f49fd0d5c8311973980fc 100644 (file)
@@ -20,28 +20,29 @@ from ._compat import string_types
 from ._compat import text_type
 from ._compat import url_quote
 
-_word_split_re = re.compile(r'(\s+)')
+_word_split_re = re.compile(r"(\s+)")
 _punctuation_re = re.compile(
-    '^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$' % (
-        '|'.join(map(re.escape, ('(', '<', '&lt;'))),
-        '|'.join(map(re.escape, ('.', ',', ')', '>', '\n', '&gt;')))
+    "^(?P<lead>(?:%s)*)(?P<middle>.*?)(?P<trail>(?:%s)*)$"
+    % (
+        "|".join(map(re.escape, ("(", "<", "&lt;"))),
+        "|".join(map(re.escape, (".", ",", ")", ">", "\n", "&gt;"))),
     )
 )
-_simple_email_re = re.compile(r'^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$')
-_striptags_re = re.compile(r'(<!--.*?-->|<[^>]*>)')
-_entity_re = re.compile(r'&([^;]+);')
-_letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
-_digits = '0123456789'
+_simple_email_re = re.compile(r"^\S+@[a-zA-Z0-9._-]+\.[a-zA-Z0-9._-]+$")
+_striptags_re = re.compile(r"(<!--.*?-->|<[^>]*>)")
+_entity_re = re.compile(r"&([^;]+);")
+_letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+_digits = "0123456789"
 
 # special singleton representing missing values for the runtime
-missing = type('MissingType', (), {'__repr__': lambda x: 'missing'})()
+missing = type("MissingType", (), {"__repr__": lambda x: "missing"})()
 
 # internal code
 internal_code = set()
 
-concat = u''.join
+concat = u"".join
 
-_slash_escape = '\\/' not in json.dumps('/')
+_slash_escape = "\\/" not in json.dumps("/")
 
 
 def contextfunction(f):
@@ -102,6 +103,7 @@ def is_undefined(obj):
             return var
     """
     from jinja2.runtime import Undefined
+
     return isinstance(obj, Undefined)
 
 
@@ -119,6 +121,7 @@ def clear_caches():
     """
     from jinja2.environment import _spontaneous_environments
     from jinja2.lexer import _lexer_cache
+
     _spontaneous_environments.clear()
     _lexer_cache.clear()
 
@@ -135,10 +138,10 @@ def import_string(import_name, silent=False):
     :return: imported object
     """
     try:
-        if ':' in import_name:
-            module, obj = import_name.split(':', 1)
-        elif '.' in import_name:
-            module, _, obj = import_name.rpartition('.')
+        if ":" in import_name:
+            module, obj = import_name.split(":", 1)
+        elif "." in import_name:
+            module, _, obj = import_name.rpartition(".")
         else:
             return __import__(import_name)
         return getattr(__import__(module, None, None, [obj]), obj)
@@ -147,7 +150,7 @@ def import_string(import_name, silent=False):
             raise
 
 
-def open_if_exists(filename, mode='rb'):
+def open_if_exists(filename, mode="rb"):
     """Returns a file descriptor for the filename if that file exists,
     otherwise ``None``.
     """
@@ -163,15 +166,15 @@ def object_type_repr(obj):
     example for `None` and `Ellipsis`).
     """
     if obj is None:
-        return 'None'
+        return "None"
     elif obj is Ellipsis:
-        return 'Ellipsis'
+        return "Ellipsis"
     # __builtin__ in 2.x, builtins in 3.x
-    if obj.__class__.__module__ in ('__builtin__', 'builtins'):
+    if obj.__class__.__module__ in ("__builtin__", "builtins"):
         name = obj.__class__.__name__
     else:
-        name = obj.__class__.__module__ + '.' + obj.__class__.__name__
-    return '%s object' % name
+        name = obj.__class__.__module__ + "." + obj.__class__.__name__
+    return "%s object" % name
 
 
 def pformat(obj, verbose=False):
@@ -180,9 +183,11 @@ def pformat(obj, verbose=False):
     """
     try:
         from pretty import pretty
+
         return pretty(obj, verbose=verbose)
     except ImportError:
         from pprint import pformat
+
         return pformat(obj)
 
 
@@ -200,45 +205,61 @@ def urlize(text, trim_url_limit=None, rel=None, target=None):
 
     If target is not None, a target attribute will be added to the link.
     """
-    trim_url = lambda x, limit=trim_url_limit: limit is not None \
-                         and (x[:limit] + (len(x) >=limit and '...'
-                         or '')) or x
+    trim_url = (
+        lambda x, limit=trim_url_limit: limit is not None
+        and (x[:limit] + (len(x) >= limit and "..." or ""))
+        or x
+    )
     words = _word_split_re.split(text_type(escape(text)))
-    rel_attr = rel and ' rel="%s"' % text_type(escape(rel)) or ''
-    target_attr = target and ' target="%s"' % escape(target) or ''
+    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:
             lead, middle, trail = match.groups()
-            if middle.startswith('www.') or (
-                '@' not in middle and
-                not middle.startswith('http://') and
-                not middle.startswith('https://') and
-                len(middle) > 0 and
-                middle[0] in _letters + _digits and (
-                    middle.endswith('.org') or
-                    middle.endswith('.net') or
-                    middle.endswith('.com')
-                )):
-                middle = '<a href="http://%s"%s%s>%s</a>' % (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,
-                    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):
+            if middle.startswith("www.") or (
+                "@" not in middle
+                and not middle.startswith("http://")
+                and not middle.startswith("https://")
+                and len(middle) > 0
+                and middle[0] in _letters + _digits
+                and (
+                    middle.endswith(".org")
+                    or middle.endswith(".net")
+                    or middle.endswith(".com")
+                )
+            ):
+                middle = '<a href="http://%s"%s%s>%s</a>' % (
+                    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,
+                    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)
             if lead + middle + trail != word:
                 words[i] = lead + middle + trail
-    return u''.join(words)
+    return u"".join(words)
 
 
 def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
     """Generate some lorem ipsum for the template."""
     from jinja2.constants import LOREM_IPSUM_WORDS
     from random import choice, randrange
+
     words = LOREM_IPSUM_WORDS.split()
     result = []
 
@@ -263,25 +284,25 @@ def generate_lorem_ipsum(n=5, html=True, min=20, max=100):
             if idx - randrange(3, 8) > last_comma:
                 last_comma = idx
                 last_fullstop += 2
-                word += ','
+                word += ","
             # add end of sentences
             if idx - randrange(10, 20) > last_fullstop:
                 last_comma = last_fullstop = idx
-                word += '.'
+                word += "."
                 next_capitalized = True
             p.append(word)
 
         # ensure that the paragraph ends with a dot.
-        p = u' '.join(p)
-        if p.endswith(','):
-            p = p[:-1] + '.'
-        elif not p.endswith('.'):
-            p += '.'
+        p = u" ".join(p)
+        if p.endswith(","):
+            p = p[:-1] + "."
+        elif not p.endswith("."):
+            p += "."
         result.append(p)
 
     if not html:
-        return u'\n\n'.join(result)
-    return Markup(u'\n'.join(u'<p>%s</p>' % escape(x) for x in result))
+        return u"\n\n".join(result)
+    return Markup(u"\n".join(u"<p>%s</p>" % escape(x) for x in result))
 
 
 def unicode_urlencode(obj, charset="utf-8", for_qs=False):
@@ -336,9 +357,9 @@ class LRUCache(object):
 
     def __getstate__(self):
         return {
-            'capacity':     self.capacity,
-            '_mapping':     self._mapping,
-            '_queue':       self._queue
+            "capacity": self.capacity,
+            "_mapping": self._mapping,
+            "_queue": self._queue,
         }
 
     def __setstate__(self, d):
@@ -390,10 +411,7 @@ class LRUCache(object):
         return len(self._mapping)
 
     def __repr__(self):
-        return '<%s %r>' % (
-            self.__class__.__name__,
-            self._mapping
-        )
+        return "<%s %r>" % (self.__class__.__name__, self._mapping)
 
     def __getitem__(self, key):
         """Get an item from the cache. Moves the item up so that it has the
@@ -462,10 +480,13 @@ class LRUCache(object):
 
     def itervalue(self):
         """Iterate over all values."""
-        warnings.warn(DeprecationWarning(
-            '"itervalue()" is deprecated and will be removed in version 2.12.'
-            + ' Use "itervalues()" instead.'
-        ), stacklevel=2)
+        warnings.warn(
+            DeprecationWarning(
+                '"itervalue()" is deprecated and will be removed in version 2.12.'
+                + ' Use "itervalues()" instead.'
+            ),
+            stacklevel=2,
+        )
         return self.itervalues()
 
     def itervalues(self):
@@ -496,10 +517,12 @@ class LRUCache(object):
 abc.MutableMapping.register(LRUCache)
 
 
-def select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
-                      disabled_extensions=(),
-                      default_for_string=True,
-                      default=False):
+def select_autoescape(
+    enabled_extensions=("html", "htm", "xml"),
+    disabled_extensions=(),
+    default_for_string=True,
+    default=False,
+):
     """Intelligently sets the initial value of autoescaping based on the
     filename of the template.  This is the recommended way to configure
     autoescaping if you do not want to write a custom function yourself.
@@ -534,10 +557,9 @@ def select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
 
     .. versionadded:: 2.9
     """
-    enabled_patterns = tuple('.' + x.lstrip('.').lower()
-                             for x in enabled_extensions)
-    disabled_patterns = tuple('.' + x.lstrip('.').lower()
-                              for x in disabled_extensions)
+    enabled_patterns = tuple("." + x.lstrip(".").lower() for x in enabled_extensions)
+    disabled_patterns = tuple("." + x.lstrip(".").lower() for x in disabled_extensions)
+
     def autoescape(template_name):
         if template_name is None:
             return default_for_string
@@ -547,6 +569,7 @@ def select_autoescape(enabled_extensions=('html', 'htm', 'xml'),
         if template_name.endswith(disabled_patterns):
             return False
         return default
+
     return autoescape
 
 
@@ -570,11 +593,13 @@ def htmlsafe_json_dumps(obj, dumper=None, **kwargs):
     """
     if dumper is None:
         dumper = json.dumps
-    rv = dumper(obj, **kwargs) \
-        .replace(u'<', u'\\u003c') \
-        .replace(u'>', u'\\u003e') \
-        .replace(u'&', u'\\u0026') \
-        .replace(u"'", u'\\u0027')
+    rv = (
+        dumper(obj, **kwargs)
+        .replace(u"<", u"\\u003c")
+        .replace(u">", u"\\u003e")
+        .replace(u"&", u"\\u0026")
+        .replace(u"'", u"\\u0027")
+    )
     return Markup(rv)
 
 
@@ -606,7 +631,7 @@ class Cycler(object):
 
     def __init__(self, *items):
         if not items:
-            raise RuntimeError('at least one item has to be provided')
+            raise RuntimeError("at least one item has to be provided")
         self.items = items
         self.pos = 0
 
@@ -635,14 +660,14 @@ class Cycler(object):
 class Joiner(object):
     """A joining helper for templates."""
 
-    def __init__(self, sep=u', '):
+    def __init__(self, sep=u", "):
         self.sep = sep
         self.used = False
 
     def __call__(self):
         if not self.used:
             self.used = True
-            return u''
+            return u""
         return self.sep
 
 
@@ -655,7 +680,7 @@ class Namespace(object):
         self.__attrs = dict(*args, **kwargs)
 
     def __getattribute__(self, name):
-        if name == '_Namespace__attrs':
+        if name == "_Namespace__attrs":
             return object.__getattribute__(self, name)
         try:
             return self.__attrs[name]
@@ -666,12 +691,12 @@ class Namespace(object):
         self.__attrs[name] = value
 
     def __repr__(self):
-        return '<Namespace %r>' % self.__attrs
+        return "<Namespace %r>" % self.__attrs
 
 
 # does this python version support async for in and async generators?
 try:
-    exec('async def _():\n async for _ in ():\n  yield _')
+    exec("async def _():\n async for _ in ():\n  yield _")
     have_async_gen = True
 except SyntaxError:
     have_async_gen = False
index 2e03a6b464db897ef0a6d63ca003dc5c93fd19e8..a803adeffa7abc7c0c988de1019108daf5c75f35 100644 (file)
@@ -28,7 +28,7 @@ class NodeVisitor(object):
         exists for this node.  In that case the generic visit function is
         used instead.
         """
-        method = 'visit_' + node.__class__.__name__
+        method = "visit_" + node.__class__.__name__
         return getattr(self, method, None)
 
     def visit(self, node, *args, **kwargs):
index c1c33c3a0cc5ca3a3fcde3e4680d2c168a7a1abd..a1c11a95f4e817ba76d55691e597260733b292ec 100644 (file)
@@ -18,105 +18,93 @@ from jinja2.utils import have_async_gen
 
 
 def pytest_ignore_collect(path):
-    if 'async' in path.basename and not have_async_gen:
+    if "async" in path.basename and not have_async_gen:
         return True
     return False
 
 
 def pytest_configure(config):
-    '''Register custom marks for test categories.'''
+    """Register custom marks for test categories."""
     custom_markers = [
-        'api',
-        'byte_code_cache',
-        'core_tags',
-        'debug',
-        'escapeUrlizeTarget',
-        'ext',
-        'extended',
-        'filesystemloader',
-        'filter',
-        'for_loop',
-        'helpers',
-        'if_condition',
-        'imports',
-        'includes',
-        'inheritance',
-        'lexer',
-        'lexnparse',
-        'loaders',
-        'loremIpsum',
-        'lowlevel',
-        'lrucache',
-        'lstripblocks',
-        'macros',
-        'meta',
-        'moduleloader',
-        'parser',
-        'regression',
-        'sandbox',
-        'set',
-        'streaming',
-        'syntax',
-        'test_tests',
-        'tokenstream',
-        'undefined',
-        'utils',
-        'with_',
+        "api",
+        "byte_code_cache",
+        "core_tags",
+        "debug",
+        "escapeUrlizeTarget",
+        "ext",
+        "extended",
+        "filesystemloader",
+        "filter",
+        "for_loop",
+        "helpers",
+        "if_condition",
+        "imports",
+        "includes",
+        "inheritance",
+        "lexer",
+        "lexnparse",
+        "loaders",
+        "loremIpsum",
+        "lowlevel",
+        "lrucache",
+        "lstripblocks",
+        "macros",
+        "meta",
+        "moduleloader",
+        "parser",
+        "regression",
+        "sandbox",
+        "set",
+        "streaming",
+        "syntax",
+        "test_tests",
+        "tokenstream",
+        "undefined",
+        "utils",
+        "with_",
     ]
     for mark in custom_markers:
-        config.addinivalue_line('markers', mark + ': test category')
+        config.addinivalue_line("markers", mark + ": test category")
 
 
 @pytest.fixture
 def env():
-    '''returns a new environment.
-    '''
+    """returns a new environment."""
     return Environment()
 
 
 @pytest.fixture
 def dict_loader():
-    '''returns DictLoader
-    '''
-    return loaders.DictLoader({
-        'justdict.html':        'FOO'
-    })
+    """returns DictLoader"""
+    return loaders.DictLoader({"justdict.html": "FOO"})
 
 
 @pytest.fixture
 def package_loader():
-    '''returns PackageLoader initialized from templates
-    '''
-    return loaders.PackageLoader('res', 'templates')
+    """returns PackageLoader initialized from templates"""
+    return loaders.PackageLoader("res", "templates")
 
 
 @pytest.fixture
 def filesystem_loader():
-    '''returns FileSystemLoader initialized to res/templates directory
-    '''
+    """returns FileSystemLoader initialized to res/templates directory"""
     here = os.path.dirname(os.path.abspath(__file__))
-    return loaders.FileSystemLoader(here + '/res/templates')
+    return loaders.FileSystemLoader(here + "/res/templates")
 
 
 @pytest.fixture
 def function_loader():
-    '''returns a FunctionLoader
-    '''
-    return loaders.FunctionLoader({'justfunction.html': 'FOO'}.get)
+    """returns a FunctionLoader"""
+    return loaders.FunctionLoader({"justfunction.html": "FOO"}.get)
 
 
 @pytest.fixture
 def choice_loader(dict_loader, package_loader):
-    '''returns a ChoiceLoader
-    '''
+    """returns a ChoiceLoader"""
     return loaders.ChoiceLoader([dict_loader, package_loader])
 
 
 @pytest.fixture
 def prefix_loader(filesystem_loader, dict_loader):
-    '''returns a PrefixLoader
-    '''
-    return loaders.PrefixLoader({
-        'a':        filesystem_loader,
-        'b':        dict_loader
-    })
+    """returns a PrefixLoader"""
+    return loaders.PrefixLoader({"a": filesystem_loader, "b": dict_loader})
diff --git a/tests/res/templates/mojibake.txt b/tests/res/templates/mojibake.txt
new file mode 100644 (file)
index 0000000..4b94aa6
--- /dev/null
@@ -0,0 +1 @@
+文字化け
diff --git a/tests/res/templates/variable_encoding.txt b/tests/res/templates/variable_encoding.txt
deleted file mode 100644 (file)
index dadbed4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-tech
\ No newline at end of file
index fff63ff6f2afddce8abf9a1a3e03828caa973ffb..a0c546c8661606ed19e669bd883b0f8130bf15fd 100644 (file)
@@ -37,18 +37,17 @@ from jinja2.utils import evalcontextfunction
 @pytest.mark.api
 @pytest.mark.extended
 class TestExtendedAPI(object):
-
     def test_item_and_attribute(self, env):
         from jinja2.sandbox import SandboxedEnvironment
 
         for env in Environment(), SandboxedEnvironment():
             # the |list is necessary for python3
-            tmpl = env.from_string('{{ foo.items()|list }}')
-            assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
+            tmpl = env.from_string("{{ foo.items()|list }}")
+            assert tmpl.render(foo={"items": 42}) == "[('items', 42)]"
             tmpl = env.from_string('{{ foo|attr("items")()|list }}')
-            assert tmpl.render(foo={'items': 42}) == "[('items', 42)]"
+            assert tmpl.render(foo={"items": 42}) == "[('items', 42)]"
             tmpl = env.from_string('{{ foo["items"] }}')
-            assert tmpl.render(foo={'items': 42}) == '42'
+            assert tmpl.render(foo={"items": 42}) == "42"
 
     def test_finalize(self):
         e = Environment(finalize=lambda v: "" if v is None else v)
@@ -128,7 +127,7 @@ class TestExtendedAPI(object):
         assert expr(foo=42) == 84
 
     def test_template_passthrough(self, env):
-        t = Template('Content')
+        t = Template("Content")
         assert env.get_template(t) is t
         assert env.select_template([t]) is t
         assert env.get_or_select_template([t]) is t
@@ -138,7 +137,7 @@ class TestExtendedAPI(object):
         """Passing Undefined to get/select_template raises an
         UndefinedError or shows the undefined message in the list.
         """
-        env.loader=DictLoader({})
+        env.loader = DictLoader({})
         t = Undefined(name="no_name_1")
 
         with pytest.raises(UndefinedError):
@@ -157,23 +156,22 @@ class TestExtendedAPI(object):
         assert "'no_name_1' is undefined" in exc_message
         assert "no_name_2" in exc_message
 
-
     def test_autoescape_autoselect(self, env):
         def select_autoescape(name):
-            if name is None or '.' not in name:
+            if name is None or "." not in name:
                 return False
-            return name.endswith('.html')
-        env = Environment(autoescape=select_autoescape,
-                          loader=DictLoader({
-                                                'test.txt':     '{{ foo }}',
-                                                'test.html':    '{{ foo }}'
-                                            }))
-        t = env.get_template('test.txt')
-        assert t.render(foo='<foo>') == '<foo>'
-        t = env.get_template('test.html')
-        assert t.render(foo='<foo>') == '&lt;foo&gt;'
-        t = env.from_string('{{ foo }}')
-        assert t.render(foo='<foo>') == '<foo>'
+            return name.endswith(".html")
+
+        env = Environment(
+            autoescape=select_autoescape,
+            loader=DictLoader({"test.txt": "{{ foo }}", "test.html": "{{ foo }}"}),
+        )
+        t = env.get_template("test.txt")
+        assert t.render(foo="<foo>") == "<foo>"
+        t = env.get_template("test.html")
+        assert t.render(foo="<foo>") == "&lt;foo&gt;"
+        t = env.from_string("{{ foo }}")
+        assert t.render(foo="<foo>") == "<foo>"
 
     def test_sandbox_max_range(self, env):
         from jinja2.sandbox import SandboxedEnvironment, MAX_RANGE
@@ -188,53 +186,56 @@ class TestExtendedAPI(object):
 @pytest.mark.api
 @pytest.mark.meta
 class TestMeta(object):
-
     def test_find_undeclared_variables(self, env):
-        ast = env.parse('{% set foo = 42 %}{{ bar + foo }}')
+        ast = env.parse("{% set foo = 42 %}{{ bar + foo }}")
         x = meta.find_undeclared_variables(ast)
-        assert x == set(['bar'])
+        assert x == set(["bar"])
 
-        ast = env.parse('{% set foo = 42 %}{{ bar + foo }}'
-                        '{% macro meh(x) %}{{ x }}{% endmacro %}'
-                        '{% for item in seq %}{{ muh(item) + meh(seq) }}'
-                        '{% endfor %}')
+        ast = env.parse(
+            "{% set foo = 42 %}{{ bar + foo }}"
+            "{% macro meh(x) %}{{ x }}{% endmacro %}"
+            "{% for item in seq %}{{ muh(item) + meh(seq) }}"
+            "{% endfor %}"
+        )
         x = meta.find_undeclared_variables(ast)
-        assert x == set(['bar', 'seq', 'muh'])
+        assert x == set(["bar", "seq", "muh"])
 
-        ast = env.parse('{% for x in range(5) %}{{ x }}{% endfor %}{{ foo }}')
+        ast = env.parse("{% for x in range(5) %}{{ x }}{% endfor %}{{ foo }}")
         x = meta.find_undeclared_variables(ast)
-        assert x == set(['foo'])
+        assert x == set(["foo"])
 
     def test_find_refererenced_templates(self, env):
         ast = env.parse('{% extends "layout.html" %}{% include helper %}')
         i = meta.find_referenced_templates(ast)
-        assert next(i) == 'layout.html'
+        assert next(i) == "layout.html"
         assert next(i) is None
         assert list(i) == []
 
-        ast = env.parse('{% extends "layout.html" %}'
-                        '{% from "test.html" import a, b as c %}'
-                        '{% import "meh.html" as meh %}'
-                        '{% include "muh.html" %}')
+        ast = env.parse(
+            '{% extends "layout.html" %}'
+            '{% from "test.html" import a, b as c %}'
+            '{% import "meh.html" as meh %}'
+            '{% include "muh.html" %}'
+        )
         i = meta.find_referenced_templates(ast)
-        assert list(i) == ['layout.html', 'test.html', 'meh.html', 'muh.html']
+        assert list(i) == ["layout.html", "test.html", "meh.html", "muh.html"]
 
     def test_find_included_templates(self, env):
         ast = env.parse('{% include ["foo.html", "bar.html"] %}')
         i = meta.find_referenced_templates(ast)
-        assert list(i) == ['foo.html', 'bar.html']
+        assert list(i) == ["foo.html", "bar.html"]
 
         ast = env.parse('{% include ("foo.html", "bar.html") %}')
         i = meta.find_referenced_templates(ast)
-        assert list(i) == ['foo.html', 'bar.html']
+        assert list(i) == ["foo.html", "bar.html"]
 
         ast = env.parse('{% include ["foo.html", "bar.html", foo] %}')
         i = meta.find_referenced_templates(ast)
-        assert list(i) == ['foo.html', 'bar.html', None]
+        assert list(i) == ["foo.html", "bar.html", None]
 
         ast = env.parse('{% include ("foo.html", "bar.html", foo) %}')
         i = meta.find_referenced_templates(ast)
-        assert list(i) == ['foo.html', 'bar.html', None]
+        assert list(i) == ["foo.html", "bar.html", None]
 
 
 @pytest.mark.api
@@ -256,8 +257,8 @@ class TestStreaming(object):
         )
         stream = tmpl.stream(seq=list(range(3)))
         stream.enable_buffering(size=3)
-        assert next(stream) == u'<ul><li>1'
-        assert next(stream) == u' - 0</li>'
+        assert next(stream) == u"<ul><li>1"
+        assert next(stream) == u" - 0</li>"
 
     def test_streaming_behavior(self, env):
         tmpl = env.from_string("")
@@ -273,9 +274,9 @@ class TestStreaming(object):
         try:
             tmpl = env.from_string(u"\u2713")
             stream = tmpl.stream()
-            stream.dump(os.path.join(tmp, 'dump.txt'), 'utf-8')
-            with open(os.path.join(tmp, 'dump.txt'), 'rb') as f:
-                assert f.read() == b'\xe2\x9c\x93'
+            stream.dump(os.path.join(tmp, "dump.txt"), "utf-8")
+            with open(os.path.join(tmp, "dump.txt"), "rb") as f:
+                assert f.read() == b"\xe2\x9c\x93"
         finally:
             shutil.rmtree(tmp)
 
@@ -283,148 +284,151 @@ class TestStreaming(object):
 @pytest.mark.api
 @pytest.mark.undefined
 class TestUndefined(object):
-
     def test_stopiteration_is_undefined(self):
         def test():
             raise StopIteration()
-        t = Template('A{{ test() }}B')
-        assert t.render(test=test) == 'AB'
-        t = Template('A{{ test().missingattribute }}B')
+
+        t = Template("A{{ test() }}B")
+        assert t.render(test=test) == "AB"
+        t = Template("A{{ test().missingattribute }}B")
         pytest.raises(UndefinedError, t.render, test=test)
 
     def test_undefined_and_special_attributes(self):
         with pytest.raises(AttributeError):
-            Undefined('Foo').__dict__
+            Undefined("Foo").__dict__
 
     def test_logging_undefined(self):
         _messages = []
 
         class DebugLogger(object):
             def warning(self, msg, *args):
-                _messages.append('W:' + msg % args)
+                _messages.append("W:" + msg % args)
 
             def error(self, msg, *args):
-                _messages.append('E:' + msg % args)
+                _messages.append("E:" + msg % args)
 
         logging_undefined = make_logging_undefined(DebugLogger())
         env = Environment(undefined=logging_undefined)
-        assert env.from_string('{{ missing }}').render() == u''
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing.attribute }}').render)
-        assert env.from_string('{{ missing|list }}').render() == '[]'
-        assert env.from_string('{{ missing is not defined }}').render() \
-            == 'True'
-        assert env.from_string('{{ foo.missing }}').render(foo=42) == ''
-        assert env.from_string('{{ not missing }}').render() == 'True'
+        assert env.from_string("{{ missing }}").render() == u""
+        pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
+        assert env.from_string("{{ missing|list }}").render() == "[]"
+        assert env.from_string("{{ missing is not defined }}").render() == "True"
+        assert env.from_string("{{ foo.missing }}").render(foo=42) == ""
+        assert env.from_string("{{ not missing }}").render() == "True"
         assert _messages == [
-            'W:Template variable warning: missing is undefined',
+            "W:Template variable warning: missing is undefined",
             "E:Template variable error: 'missing' is undefined",
-            'W:Template variable warning: missing is undefined',
-            'W:Template variable warning: int object has no attribute missing',
-            'W:Template variable warning: missing is undefined',
+            "W:Template variable warning: missing is undefined",
+            "W:Template variable warning: int object has no attribute missing",
+            "W:Template variable warning: missing is undefined",
         ]
 
     def test_default_undefined(self):
         env = Environment(undefined=Undefined)
-        assert env.from_string('{{ missing }}').render() == u''
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing.attribute }}').render)
-        assert env.from_string('{{ missing|list }}').render() == '[]'
-        assert env.from_string('{{ missing is not defined }}').render() \
-            == 'True'
-        assert env.from_string('{{ foo.missing }}').render(foo=42) == ''
-        assert env.from_string('{{ not missing }}').render() == 'True'
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing - 1}}').render)
-        und1 = Undefined(name='x')
-        und2 = Undefined(name='y')
+        assert env.from_string("{{ missing }}").render() == u""
+        pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
+        assert env.from_string("{{ missing|list }}").render() == "[]"
+        assert env.from_string("{{ missing is not defined }}").render() == "True"
+        assert env.from_string("{{ foo.missing }}").render(foo=42) == ""
+        assert env.from_string("{{ not missing }}").render() == "True"
+        pytest.raises(UndefinedError, env.from_string("{{ missing - 1}}").render)
+        und1 = Undefined(name="x")
+        und2 = Undefined(name="y")
         assert und1 == und2
         assert und1 != 42
         assert hash(und1) == hash(und2) == hash(Undefined())
         with pytest.raises(AttributeError):
-            getattr(Undefined, '__slots__')
+            getattr(Undefined, "__slots__")
 
     def test_chainable_undefined(self):
         env = Environment(undefined=ChainableUndefined)
         # The following tests are copied from test_default_undefined
-        assert env.from_string('{{ missing }}').render() == u''
-        assert env.from_string('{{ missing|list }}').render() == '[]'
-        assert env.from_string('{{ missing is not defined }}').render() \
-            == 'True'
-        assert env.from_string('{{ foo.missing }}').render(foo=42) == ''
-        assert env.from_string('{{ not missing }}').render() == 'True'
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing - 1}}').render)
+        assert env.from_string("{{ missing }}").render() == u""
+        assert env.from_string("{{ missing|list }}").render() == "[]"
+        assert env.from_string("{{ missing is not defined }}").render() == "True"
+        assert env.from_string("{{ foo.missing }}").render(foo=42) == ""
+        assert env.from_string("{{ not missing }}").render() == "True"
+        pytest.raises(UndefinedError, env.from_string("{{ missing - 1}}").render)
         with pytest.raises(AttributeError):
-            getattr(ChainableUndefined, '__slots__')
+            getattr(ChainableUndefined, "__slots__")
 
         # The following tests ensure subclass functionality works as expected
-        assert env.from_string('{{ missing.bar["baz"] }}').render() == u''
-        assert env.from_string('{{ foo.bar["baz"]._undefined_name }}').render() \
-            == u'foo'
-        assert env.from_string('{{ foo.bar["baz"]._undefined_name }}').render(
-            foo=42) == u'bar'
-        assert env.from_string('{{ foo.bar["baz"]._undefined_name }}').render(
-            foo={'bar': 42}) == u'baz'
+        assert env.from_string('{{ missing.bar["baz"] }}').render() == u""
+        assert (
+            env.from_string('{{ foo.bar["baz"]._undefined_name }}').render() == u"foo"
+        )
+        assert (
+            env.from_string('{{ foo.bar["baz"]._undefined_name }}').render(foo=42)
+            == u"bar"
+        )
+        assert (
+            env.from_string('{{ foo.bar["baz"]._undefined_name }}').render(
+                foo={"bar": 42}
+            )
+            == u"baz"
+        )
 
     def test_debug_undefined(self):
         env = Environment(undefined=DebugUndefined)
-        assert env.from_string('{{ missing }}').render() == '{{ missing }}'
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing.attribute }}').render)
-        assert env.from_string('{{ missing|list }}').render() == '[]'
-        assert env.from_string('{{ missing is not defined }}').render() \
-            == 'True'
-        assert env.from_string('{{ foo.missing }}').render(foo=42) \
+        assert env.from_string("{{ missing }}").render() == "{{ missing }}"
+        pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
+        assert env.from_string("{{ missing|list }}").render() == "[]"
+        assert env.from_string("{{ missing is not defined }}").render() == "True"
+        assert (
+            env.from_string("{{ foo.missing }}").render(foo=42)
             == u"{{ no such element: int object['missing'] }}"
-        assert env.from_string('{{ not missing }}').render() == 'True'
-        undefined_hint = 'this is testing undefined hint of DebugUndefined'
-        assert str(DebugUndefined(hint=undefined_hint)) == u'{{ undefined value printed: %s }}' % undefined_hint
+        )
+        assert env.from_string("{{ not missing }}").render() == "True"
+        undefined_hint = "this is testing undefined hint of DebugUndefined"
+        assert (
+            str(DebugUndefined(hint=undefined_hint))
+            == u"{{ undefined value printed: %s }}" % undefined_hint
+        )
         with pytest.raises(AttributeError):
-            getattr(DebugUndefined, '__slots__')
+            getattr(DebugUndefined, "__slots__")
 
     def test_strict_undefined(self):
         env = Environment(undefined=StrictUndefined)
-        pytest.raises(UndefinedError, env.from_string('{{ missing }}').render)
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing.attribute }}').render)
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ missing|list }}').render)
-        assert env.from_string('{{ missing is not defined }}').render() \
-            == 'True'
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ foo.missing }}').render, foo=42)
-        pytest.raises(UndefinedError,
-                      env.from_string('{{ not missing }}').render)
-        assert env.from_string('{{ missing|default("default", true) }}')\
-            .render() == 'default'
+        pytest.raises(UndefinedError, env.from_string("{{ missing }}").render)
+        pytest.raises(UndefinedError, env.from_string("{{ missing.attribute }}").render)
+        pytest.raises(UndefinedError, env.from_string("{{ missing|list }}").render)
+        assert env.from_string("{{ missing is not defined }}").render() == "True"
+        pytest.raises(
+            UndefinedError, env.from_string("{{ foo.missing }}").render, foo=42
+        )
+        pytest.raises(UndefinedError, env.from_string("{{ not missing }}").render)
+        assert (
+            env.from_string('{{ missing|default("default", true) }}').render()
+            == "default"
+        )
         with pytest.raises(AttributeError):
-            getattr(StrictUndefined, '__slots__')
-        assert env.from_string('{{ "foo" if false }}').render() == ''
+            getattr(StrictUndefined, "__slots__")
+        assert env.from_string('{{ "foo" if false }}').render() == ""
 
     def test_indexing_gives_undefined(self):
         t = Template("{{ var[42].foo }}")
         pytest.raises(UndefinedError, t.render, var=0)
 
     def test_none_gives_proper_error(self):
-        with pytest.raises(UndefinedError, match= "'None' has no attribute 'split'"):
-            Environment().getattr(None, 'split')()
+        with pytest.raises(UndefinedError, match="'None' has no attribute 'split'"):
+            Environment().getattr(None, "split")()
 
     def test_object_repr(self):
-        with pytest.raises(UndefinedError, match="'int object' has no attribute 'upper'"):
-            Undefined(obj=42, name='upper')()
+        with pytest.raises(
+            UndefinedError, match="'int object' has no attribute 'upper'"
+        ):
+            Undefined(obj=42, name="upper")()
 
 
 @pytest.mark.api
 @pytest.mark.lowlevel
 class TestLowLevel(object):
-
     def test_custom_code_generator(self):
         class CustomCodeGenerator(CodeGenerator):
             def visit_Const(self, node, frame=None):
                 # This method is pure nonsense, but works fine for testing...
-                if node.value == 'foo':
-                    self.write(repr('bar'))
+                if node.value == "foo":
+                    self.write(repr("bar"))
                 else:
                     super(CustomCodeGenerator, self).visit_Const(node, frame)
 
@@ -433,16 +437,16 @@ class TestLowLevel(object):
 
         env = CustomEnvironment()
         tmpl = env.from_string('{% set foo = "foo" %}{{ foo }}')
-        assert tmpl.render() == 'bar'
+        assert tmpl.render() == "bar"
 
     def test_custom_context(self):
         class CustomContext(Context):
             def resolve_or_missing(self, key):
-                return 'resolve-' + key
+                return "resolve-" + key
 
         class CustomEnvironment(Environment):
             context_class = CustomContext
 
         env = CustomEnvironment()
-        tmpl = env.from_string('{{ foo }}')
-        assert tmpl.render() == 'resolve-foo'
+        tmpl = env.from_string("{{ foo }}")
+        assert tmpl.render() == "resolve-foo"
index 2e0728ded246a5392673b9740c3d47b43d185e44..bae73c6ef53d5aa2d45411b5321843b1a2de0733 100644 (file)
@@ -17,18 +17,19 @@ def run(coro):
 
 
 def test_basic_async():
-    t = Template('{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}',
-                 enable_async=True)
+    t = Template(
+        "{% for item in [1, 2, 3] %}[{{ item }}]{% endfor %}", enable_async=True
+    )
+
     async def func():
         return await t.render_async()
 
     rv = run(func())
-    assert rv == '[1][2][3]'
+    assert rv == "[1][2][3]"
 
 
 def test_await_on_calls():
-    t = Template('{{ async_func() + normal_func() }}',
-                 enable_async=True)
+    t = Template("{{ async_func() + normal_func() }}", enable_async=True)
 
     async def async_func():
         return 42
@@ -37,18 +38,14 @@ def test_await_on_calls():
         return 23
 
     async def func():
-        return await t.render_async(
-            async_func=async_func,
-            normal_func=normal_func
-        )
+        return await t.render_async(async_func=async_func, normal_func=normal_func)
 
     rv = run(func())
-    assert rv == '65'
+    assert rv == "65"
 
 
 def test_await_on_calls_normal_render():
-    t = Template('{{ async_func() + normal_func() }}',
-                 enable_async=True)
+    t = Template("{{ async_func() + normal_func() }}", enable_async=True)
 
     async def async_func():
         return 42
@@ -56,17 +53,16 @@ def test_await_on_calls_normal_render():
     def normal_func():
         return 23
 
-    rv = t.render(
-        async_func=async_func,
-        normal_func=normal_func
-    )
+    rv = t.render(async_func=async_func, normal_func=normal_func)
 
-    assert rv == '65'
+    assert rv == "65"
 
 
 def test_await_and_macros():
-    t = Template('{% macro foo(x) %}[{{ x }}][{{ async_func() }}]'
-                 '{% endmacro %}{{ foo(42) }}', enable_async=True)
+    t = Template(
+        "{% macro foo(x) %}[{{ x }}][{{ async_func() }}]{% endmacro %}{{ foo(42) }}",
+        enable_async=True,
+    )
 
     async def async_func():
         return 42
@@ -75,34 +71,38 @@ def test_await_and_macros():
         return await t.render_async(async_func=async_func)
 
     rv = run(func())
-    assert rv == '[42][42]'
+    assert rv == "[42][42]"
 
 
 def test_async_blocks():
-    t = Template('{% block foo %}<Test>{% endblock %}{{ self.foo() }}',
-                 enable_async=True, autoescape=True)
+    t = Template(
+        "{% block foo %}<Test>{% endblock %}{{ self.foo() }}",
+        enable_async=True,
+        autoescape=True,
+    )
+
     async def func():
         return await t.render_async()
 
     rv = run(func())
-    assert rv == '<Test><Test>'
+    assert rv == "<Test><Test>"
 
 
 def test_async_generate():
-    t = Template('{% for x in [1, 2, 3] %}{{ x }}{% endfor %}',
-                 enable_async=True)
+    t = Template("{% for x in [1, 2, 3] %}{{ x }}{% endfor %}", enable_async=True)
     rv = list(t.generate())
-    assert rv == ['1', '2', '3']
+    assert rv == ["1", "2", "3"]
 
 
 def test_async_iteration_in_templates():
-    t = Template('{% for x in rng %}{{ x }}{% endfor %}',
-                 enable_async=True)
+    t = Template("{% for x in rng %}{{ x }}{% endfor %}", enable_async=True)
+
     async def async_iterator():
         for item in [1, 2, 3]:
             yield item
+
     rv = list(t.generate(rng=async_iterator()))
-    assert rv == ['1', '2', '3']
+    assert rv == ["1", "2", "3"]
 
 
 def test_async_iteration_in_templates_extended():
@@ -116,39 +116,43 @@ def test_async_iteration_in_templates_extended():
 
 @pytest.fixture
 def test_env_async():
-    env = Environment(loader=DictLoader(dict(
-        module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}',
-        header='[{{ foo }}|{{ 23 }}]',
-        o_printer='({{ o }})'
-    )), enable_async=True)
-    env.globals['bar'] = 23
+    env = Environment(
+        loader=DictLoader(
+            dict(
+                module="{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}",
+                header="[{{ foo }}|{{ 23 }}]",
+                o_printer="({{ o }})",
+            )
+        ),
+        enable_async=True,
+    )
+    env.globals["bar"] = 23
     return env
 
 
 @pytest.mark.imports
 class TestAsyncImports(object):
-
     def test_context_imports(self, test_env_async):
         t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}')
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env_async.from_string(
             '{% import "module" as m without context %}{{ m.test() }}'
         )
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env_async.from_string(
             '{% import "module" as m with context %}{{ m.test() }}'
         )
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
         t = test_env_async.from_string('{% from "module" import test %}{{ test() }}')
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env_async.from_string(
             '{% from "module" import test without context %}{{ test() }}'
         )
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env_async.from_string(
             '{% from "module" import test with context %}{{ test() }}'
         )
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
 
     def test_trailing_comma(self, test_env_async):
         test_env_async.from_string('{% from "foo" import bar, baz with context %}')
@@ -158,83 +162,92 @@ class TestAsyncImports(object):
         test_env_async.from_string('{% from "foo" import bar, with with context %}')
 
     def test_exports(self, test_env_async):
-        m = run(test_env_async.from_string('''
+        m = run(
+            test_env_async.from_string(
+                """
             {% macro toplevel() %}...{% endmacro %}
             {% macro __private() %}...{% endmacro %}
             {% set variable = 42 %}
             {% for item in [1] %}
                 {% macro notthere() %}{% endmacro %}
             {% endfor %}
-        ''')._get_default_module_async())
-        assert run(m.toplevel()) == '...'
-        assert not hasattr(m, '__missing')
+        """
+            )._get_default_module_async()
+        )
+        assert run(m.toplevel()) == "..."
+        assert not hasattr(m, "__missing")
         assert m.variable == 42
-        assert not hasattr(m, 'notthere')
+        assert not hasattr(m, "notthere")
 
 
 @pytest.mark.imports
 @pytest.mark.includes
 class TestAsyncIncludes(object):
-
     def test_context_include(self, test_env_async):
         t = test_env_async.from_string('{% include "header" %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
         t = test_env_async.from_string('{% include "header" with context %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
         t = test_env_async.from_string('{% include "header" without context %}')
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
 
     def test_choice_includes(self, test_env_async):
         t = test_env_async.from_string('{% include ["missing", "header"] %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
 
         t = test_env_async.from_string(
             '{% include ["missing", "missing2"] ignore missing %}'
         )
-        assert t.render(foo=42) == ''
+        assert t.render(foo=42) == ""
 
         t = test_env_async.from_string('{% include ["missing", "missing2"] %}')
         pytest.raises(TemplateNotFound, t.render)
         with pytest.raises(TemplatesNotFound) as e:
             t.render()
 
-        assert e.value.templates == ['missing', 'missing2']
-        assert e.value.name == 'missing2'
+        assert e.value.templates == ["missing", "missing2"]
+        assert e.value.name == "missing2"
 
         def test_includes(t, **ctx):
-            ctx['foo'] = 42
-            assert t.render(ctx) == '[42|23]'
+            ctx["foo"] = 42
+            assert t.render(ctx) == "[42|23]"
 
         t = test_env_async.from_string('{% include ["missing", "header"] %}')
         test_includes(t)
-        t = test_env_async.from_string('{% include x %}')
-        test_includes(t, x=['missing', 'header'])
+        t = test_env_async.from_string("{% include x %}")
+        test_includes(t, x=["missing", "header"])
         t = test_env_async.from_string('{% include [x, "header"] %}')
-        test_includes(t, x='missing')
-        t = test_env_async.from_string('{% include x %}')
-        test_includes(t, x='header')
-        t = test_env_async.from_string('{% include x %}')
-        test_includes(t, x='header')
-        t = test_env_async.from_string('{% include [x] %}')
-        test_includes(t, x='header')
+        test_includes(t, x="missing")
+        t = test_env_async.from_string("{% include x %}")
+        test_includes(t, x="header")
+        t = test_env_async.from_string("{% include x %}")
+        test_includes(t, x="header")
+        t = test_env_async.from_string("{% include [x] %}")
+        test_includes(t, x="header")
 
     def test_include_ignoring_missing(self, test_env_async):
         t = test_env_async.from_string('{% include "missing" %}')
         pytest.raises(TemplateNotFound, t.render)
-        for extra in '', 'with context', 'without context':
-            t = test_env_async.from_string('{% include "missing" ignore missing ' +
-                                     extra + ' %}')
-            assert t.render() == ''
+        for extra in "", "with context", "without context":
+            t = test_env_async.from_string(
+                '{% include "missing" ignore missing ' + extra + " %}"
+            )
+            assert t.render() == ""
 
     def test_context_include_with_overrides(self, test_env_async):
-        env = Environment(loader=DictLoader(dict(
-            main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
-            item="{{ item }}"
-        )))
+        env = Environment(
+            loader=DictLoader(
+                dict(
+                    main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
+                    item="{{ item }}",
+                )
+            )
+        )
         assert env.get_template("main").render() == "123"
 
     def test_unoptimized_scopes(self, test_env_async):
-        t = test_env_async.from_string("""
+        t = test_env_async.from_string(
+            """
             {% macro outer(o) %}
             {% macro inner() %}
             {% include "o_printer" %}
@@ -242,14 +255,18 @@ class TestAsyncIncludes(object):
             {{ inner() }}
             {% endmacro %}
             {{ outer("FOO") }}
-        """)
-        assert t.render().strip() == '(FOO)'
+        """
+        )
+        assert t.render().strip() == "(FOO)"
 
     def test_unoptimized_scopes_autoescape(self):
-        env = Environment(loader=DictLoader(dict(
-            o_printer='({{ o }})',
-        )), autoescape=True, enable_async=True)
-        t = env.from_string("""
+        env = Environment(
+            loader=DictLoader(dict(o_printer="({{ o }})",)),
+            autoescape=True,
+            enable_async=True,
+        )
+        t = env.from_string(
+            """
             {% macro outer(o) %}
             {% macro inner() %}
             {% include "o_printer" %}
@@ -257,26 +274,29 @@ class TestAsyncIncludes(object):
             {{ inner() }}
             {% endmacro %}
             {{ outer("FOO") }}
-        """)
-        assert t.render().strip() == '(FOO)'
+        """
+        )
+        assert t.render().strip() == "(FOO)"
 
 
 @pytest.mark.core_tags
 @pytest.mark.for_loop
 class TestAsyncForLoop(object):
-
     def test_simple(self, test_env_async):
-        tmpl = test_env_async.from_string('{% for item in seq %}{{ item }}{% endfor %}')
-        assert tmpl.render(seq=list(range(10))) == '0123456789'
+        tmpl = test_env_async.from_string("{% for item in seq %}{{ item }}{% endfor %}")
+        assert tmpl.render(seq=list(range(10))) == "0123456789"
 
     def test_else(self, test_env_async):
         tmpl = test_env_async.from_string(
-            '{% for item in seq %}XXX{% else %}...{% endfor %}')
-        assert tmpl.render() == '...'
+            "{% for item in seq %}XXX{% else %}...{% endfor %}"
+        )
+        assert tmpl.render() == "..."
 
     def test_empty_blocks(self, test_env_async):
-        tmpl = test_env_async.from_string('<{% for item in seq %}{% else %}{% endfor %}>')
-        assert tmpl.render() == '<>'
+        tmpl = test_env_async.from_string(
+            "<{% for item in seq %}{% else %}{% endfor %}>"
+        )
+        assert tmpl.render() == "<>"
 
     @pytest.mark.parametrize(
         "transform", [lambda x: x, iter, reversed, lambda x: (i for i in x), auto_aiter]
@@ -291,29 +311,35 @@ class TestAsyncForLoop(object):
         assert out == "1|0|2|1|True|False|2\n2|1|1|0|False|True|2\n"
 
     def test_cycling(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq %}{{
+        tmpl = test_env_async.from_string(
+            """{% for item in seq %}{{
             loop.cycle('<1>', '<2>') }}{% endfor %}{%
-            for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''')
-        output = tmpl.render(seq=list(range(4)), through=('<1>', '<2>'))
-        assert output == '<1><2>' * 4
+            for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
+        )
+        output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
+        assert output == "<1><2>" * 4
 
     def test_lookaround(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq -%}
+        tmpl = test_env_async.from_string(
+            """{% for item in seq -%}
             {{ loop.previtem|default('x') }}-{{ item }}-{{
             loop.nextitem|default('x') }}|
-        {%- endfor %}''')
+        {%- endfor %}"""
+        )
         output = tmpl.render(seq=list(range(4)))
-        assert output == 'x-0-1|0-1-2|1-2-3|2-3-x|'
+        assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
 
     def test_changed(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq -%}
+        tmpl = test_env_async.from_string(
+            """{% for item in seq -%}
             {{ loop.changed(item) }},
-        {%- endfor %}''')
+        {%- endfor %}"""
+        )
         output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
-        assert output == 'True,False,True,True,False,True,True,False,False,'
+        assert output == "True,False,True,True,False,True,True,False,False,"
 
     def test_scope(self, test_env_async):
-        tmpl = test_env_async.from_string('{% for item in seq %}{% endfor %}{{ item }}')
+        tmpl = test_env_async.from_string("{% for item in seq %}{% endfor %}{{ item }}")
         output = tmpl.render(seq=list(range(10)))
         assert not output
 
@@ -321,111 +347,160 @@ class TestAsyncForLoop(object):
         def inner():
             for item in range(5):
                 yield item
-        tmpl = test_env_async.from_string('{% for item in iter %}{{ item }}{% endfor %}')
+
+        tmpl = test_env_async.from_string(
+            "{% for item in iter %}{{ item }}{% endfor %}"
+        )
         output = tmpl.render(iter=inner())
-        assert output == '01234'
+        assert output == "01234"
 
     def test_noniter(self, test_env_async):
-        tmpl = test_env_async.from_string('{% for item in none %}...{% endfor %}')
+        tmpl = test_env_async.from_string("{% for item in none %}...{% endfor %}")
         pytest.raises(TypeError, tmpl.render)
 
     def test_recursive(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq recursive -%}
+        tmpl = test_env_async.from_string(
+            """{% for item in seq recursive -%}
             [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[1<[1][2]>][2<[1][2]>][3<[a]>]"
+        )
 
     def test_recursive_lookaround(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq recursive -%}
+        tmpl = test_env_async.from_string(
+            """{% for item in seq recursive -%}
             [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
             item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
             }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
+        )
 
     def test_recursive_depth0(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq recursive -%}
+        tmpl = test_env_async.from_string(
+            """{% for item in seq recursive -%}
             [{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
+        )
 
     def test_recursive_depth(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in seq recursive -%}
+        tmpl = test_env_async.from_string(
+            """{% for item in seq recursive -%}
             [{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
+        )
 
     def test_looploop(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for row in table %}
+        tmpl = test_env_async.from_string(
+            """{% for row in table %}
             {%- set rowloop = loop -%}
             {% for cell in row -%}
                 [{{ rowloop.index }}|{{ loop.index }}]
             {%- endfor %}
-        {%- endfor %}''')
-        assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
+        {%- endfor %}"""
+        )
+        assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
 
     def test_reversed_bug(self, test_env_async):
-        tmpl = test_env_async.from_string('{% for i in items %}{{ i }}'
-                               '{% if not loop.last %}'
-                               ',{% endif %}{% endfor %}')
-        assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
+        tmpl = test_env_async.from_string(
+            "{% for i in items %}{{ i }}"
+            "{% if not loop.last %}"
+            ",{% endif %}{% endfor %}"
+        )
+        assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
 
     def test_loop_errors(self, test_env_async):
-        tmpl = test_env_async.from_string('''{% for item in [1] if loop.index
-                                      == 0 %}...{% endfor %}''')
+        tmpl = test_env_async.from_string(
+            """{% for item in [1] if loop.index
+                                      == 0 %}...{% endfor %}"""
+        )
         pytest.raises(UndefinedError, tmpl.render)
-        tmpl = test_env_async.from_string('''{% for item in [] %}...{% else
-            %}{{ loop }}{% endfor %}''')
-        assert tmpl.render() == ''
+        tmpl = test_env_async.from_string(
+            """{% for item in [] %}...{% else
+            %}{{ loop }}{% endfor %}"""
+        )
+        assert tmpl.render() == ""
 
     def test_loop_filter(self, test_env_async):
-        tmpl = test_env_async.from_string('{% for item in range(10) if item '
-                               'is even %}[{{ item }}]{% endfor %}')
-        assert tmpl.render() == '[0][2][4][6][8]'
-        tmpl = test_env_async.from_string('''
+        tmpl = test_env_async.from_string(
+            "{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
+        )
+        assert tmpl.render() == "[0][2][4][6][8]"
+        tmpl = test_env_async.from_string(
+            """
             {%- for item in range(10) if item is even %}[{{
-                loop.index }}:{{ item }}]{% endfor %}''')
-        assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
+                loop.index }}:{{ item }}]{% endfor %}"""
+        )
+        assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
 
     def test_scoped_special_var(self, test_env_async):
         t = test_env_async.from_string(
-            '{% for s in seq %}[{{ loop.first }}{% for c in s %}'
-            '|{{ loop.first }}{% endfor %}]{% endfor %}')
-        assert t.render(seq=('ab', 'cd')) \
-            == '[True|True|False][False|True|False]'
+            "{% for s in seq %}[{{ loop.first }}{% for c in s %}"
+            "|{{ loop.first }}{% endfor %}]{% endfor %}"
+        )
+        assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
 
     def test_scoped_loop_var(self, test_env_async):
-        t = test_env_async.from_string('{% for x in seq %}{{ loop.first }}'
-                            '{% for y in seq %}{% endfor %}{% endfor %}')
-        assert t.render(seq='ab') == 'TrueFalse'
-        t = test_env_async.from_string('{% for x in seq %}{% for y in seq %}'
-                            '{{ loop.first }}{% endfor %}{% endfor %}')
-        assert t.render(seq='ab') == 'TrueFalseTrueFalse'
+        t = test_env_async.from_string(
+            "{% for x in seq %}{{ loop.first }}"
+            "{% for y in seq %}{% endfor %}{% endfor %}"
+        )
+        assert t.render(seq="ab") == "TrueFalse"
+        t = test_env_async.from_string(
+            "{% for x in seq %}{% for y in seq %}"
+            "{{ loop.first }}{% endfor %}{% endfor %}"
+        )
+        assert t.render(seq="ab") == "TrueFalseTrueFalse"
 
     def test_recursive_empty_loop_iter(self, test_env_async):
-        t = test_env_async.from_string('''
+        t = test_env_async.from_string(
+            """
         {%- for item in foo recursive -%}{%- endfor -%}
-        ''')
-        assert t.render(dict(foo=[])) == ''
+        """
+        )
+        assert t.render(dict(foo=[])) == ""
 
     def test_call_in_loop(self, test_env_async):
-        t = test_env_async.from_string('''
+        t = test_env_async.from_string(
+            """
         {%- macro do_something() -%}
             [{{ caller() }}]
         {%- endmacro %}
@@ -435,24 +510,29 @@ class TestAsyncForLoop(object):
                 {{ i }}
             {%- endcall %}
         {%- endfor -%}
-        ''')
-        assert t.render() == '[1][2][3]'
+        """
+        )
+        assert t.render() == "[1][2][3]"
 
     def test_scoping_bug(self, test_env_async):
-        t = test_env_async.from_string('''
+        t = test_env_async.from_string(
+            """
         {%- for item in foo %}...{{ item }}...{% endfor %}
         {%- macro item(a) %}...{{ a }}...{% endmacro %}
         {{- item(2) -}}
-        ''')
-        assert t.render(foo=(1,)) == '...1......2...'
+        """
+        )
+        assert t.render(foo=(1,)) == "...1......2..."
 
     def test_unpacking(self, test_env_async):
-        tmpl = test_env_async.from_string('{% for a, b, c in [[1, 2, 3]] %}'
-                               '{{ a }}|{{ b }}|{{ c }}{% endfor %}')
-        assert tmpl.render() == '1|2|3'
+        tmpl = test_env_async.from_string(
+            "{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
+        )
+        assert tmpl.render() == "1|2|3"
 
     def test_recursive_loop_filter(self, test_env_async):
-        t = test_env_async.from_string('''
+        t = test_env_async.from_string(
+            """
         <?xml version="1.0" encoding="UTF-8"?>
         <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
           {%- for page in [site.root] if page.url != this recursive %}
@@ -460,46 +540,46 @@ class TestAsyncForLoop(object):
           {{- loop(page.children) }}
           {%- endfor %}
         </urlset>
-        ''')
-        sm  =t.render(this='/foo', site={'root': {
-            'url': '/',
-            'children': [
-                {'url': '/foo'},
-                {'url': '/bar'},
-            ]
-        }})
+        """
+        )
+        sm = t.render(
+            this="/foo",
+            site={
+                "root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"},]}
+            },
+        )
         lines = [x.strip() for x in sm.splitlines() if x.strip()]
         assert lines == [
             '<?xml version="1.0" encoding="UTF-8"?>',
             '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
-            '<url><loc>/</loc></url>',
-            '<url><loc>/bar</loc></url>',
-            '</urlset>',
+            "<url><loc>/</loc></url>",
+            "<url><loc>/bar</loc></url>",
+            "</urlset>",
         ]
 
     def test_nonrecursive_loop_filter(self, test_env_async):
-        t = test_env_async.from_string('''
+        t = test_env_async.from_string(
+            """
         <?xml version="1.0" encoding="UTF-8"?>
         <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
           {%- for page in items if page.url != this %}
           <url><loc>{{ page.url }}</loc></url>
           {%- endfor %}
         </urlset>
-        ''')
-        sm  =t.render(this='/foo', items=[
-            {'url': '/'},
-            {'url': '/foo'},
-            {'url': '/bar'},
-        ])
+        """
+        )
+        sm = t.render(
+            this="/foo", items=[{"url": "/"}, {"url": "/foo"}, {"url": "/bar"},]
+        )
         lines = [x.strip() for x in sm.splitlines() if x.strip()]
         assert lines == [
             '<?xml version="1.0" encoding="UTF-8"?>',
             '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
-            '<url><loc>/</loc></url>',
-            '<url><loc>/bar</loc></url>',
-            '</urlset>',
+            "<url><loc>/</loc></url>",
+            "<url><loc>/bar</loc></url>",
+            "</urlset>",
         ]
 
     def test_bare_async(self, test_env_async):
         t = test_env_async.from_string('{% extends "header" %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
index 12b4e4ffe9b2f3de96d1d2ae970707e59b23e26b..23a1001d7b22aa684fa30d8b7ffa448564198f73 100644 (file)
@@ -11,10 +11,10 @@ async def make_aiter(iter):
 
 def mark_dualiter(parameter, factory):
     def decorator(f):
-        return pytest.mark.parametrize(parameter, [
-            lambda: factory(),
-            lambda: make_aiter(factory()),
-        ])(f)
+        return pytest.mark.parametrize(
+            parameter, [lambda: factory(), lambda: make_aiter(factory()),]
+        )(f)
+
     return decorator
 
 
@@ -23,39 +23,46 @@ def env_async():
     return Environment(enable_async=True)
 
 
-@mark_dualiter('foo', lambda: range(10))
+@mark_dualiter("foo", lambda: range(10))
 def test_first(env_async, foo):
-    tmpl = env_async.from_string('{{ foo()|first }}')
+    tmpl = env_async.from_string("{{ foo()|first }}")
     out = tmpl.render(foo=foo)
-    assert out == '0'
-
-
-@mark_dualiter('items', lambda: [
-    {'foo': 1, 'bar': 2},
-    {'foo': 2, 'bar': 3},
-    {'foo': 1, 'bar': 1},
-    {'foo': 3, 'bar': 4}
-])
+    assert out == "0"
+
+
+@mark_dualiter(
+    "items",
+    lambda: [
+        {"foo": 1, "bar": 2},
+        {"foo": 2, "bar": 3},
+        {"foo": 1, "bar": 1},
+        {"foo": 3, "bar": 4},
+    ],
+)
 def test_groupby(env_async, items):
-    tmpl = env_async.from_string('''
+    tmpl = env_async.from_string(
+        """
     {%- for grouper, list in items()|groupby('foo') -%}
         {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
-    {%- endfor %}''')
-    assert tmpl.render(items=items).split('|') == [
+    {%- endfor %}"""
+    )
+    assert tmpl.render(items=items).split("|") == [
         "1: 1, 2: 1, 1",
         "2: 2, 3",
         "3: 3, 4",
-        ""
+        "",
     ]
 
 
-@mark_dualiter('items', lambda: [('a', 1), ('a', 2), ('b', 1)])
+@mark_dualiter("items", lambda: [("a", 1), ("a", 2), ("b", 1)])
 def test_groupby_tuple_index(env_async, items):
-    tmpl = env_async.from_string('''
+    tmpl = env_async.from_string(
+        """
     {%- for grouper, list in items()|groupby(0) -%}
         {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
-    {%- endfor %}''')
-    assert tmpl.render(items=items) == 'a:1:2|b:1|'
+    {%- endfor %}"""
+    )
+    assert tmpl.render(items=items) == "a:1:2|b:1|"
 
 
 def make_articles():
@@ -71,80 +78,78 @@ def make_articles():
             self.title = title
 
     return [
-        Article('aha', 1, 1, 1970),
-        Article('interesting', 2, 1, 1970),
-        Article('really?', 3, 1, 1970),
-        Article('totally not', 1, 1, 1971)
+        Article("aha", 1, 1, 1970),
+        Article("interesting", 2, 1, 1970),
+        Article("really?", 3, 1, 1970),
+        Article("totally not", 1, 1, 1971),
     ]
 
 
-@mark_dualiter('articles', make_articles)
+@mark_dualiter("articles", make_articles)
 def test_groupby_multidot(env_async, articles):
-    tmpl = env_async.from_string('''
+    tmpl = env_async.from_string(
+        """
     {%- for year, list in articles()|groupby('date.year') -%}
         {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
-    {%- endfor %}''')
-    assert tmpl.render(articles=articles).split('|') == [
-        '1970[aha][interesting][really?]',
-        '1971[totally not]',
-        ''
+    {%- endfor %}"""
+    )
+    assert tmpl.render(articles=articles).split("|") == [
+        "1970[aha][interesting][really?]",
+        "1971[totally not]",
+        "",
     ]
 
 
-@mark_dualiter('int_items', lambda: [1, 2, 3])
+@mark_dualiter("int_items", lambda: [1, 2, 3])
 def test_join_env_int(env_async, int_items):
     tmpl = env_async.from_string('{{ items()|join("|") }}')
     out = tmpl.render(items=int_items)
-    assert out == '1|2|3'
+    assert out == "1|2|3"
 
 
-@mark_dualiter('string_items', lambda: ["<foo>", Markup("<span>foo</span>")])
+@mark_dualiter("string_items", lambda: ["<foo>", Markup("<span>foo</span>")])
 def test_join_string_list(string_items):
     env2 = Environment(autoescape=True, enable_async=True)
-    tmpl = env2.from_string(
-        '{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
-    assert tmpl.render(items=string_items) == '&lt;foo&gt;<span>foo</span>'
+    tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
+    assert tmpl.render(items=string_items) == "&lt;foo&gt;<span>foo</span>"
 
 
 def make_users():
     class User(object):
         def __init__(self, username):
             self.username = username
-    return map(User, ['foo', 'bar'])
+
+    return map(User, ["foo", "bar"])
 
 
-@mark_dualiter('users', make_users)
+@mark_dualiter("users", make_users)
 def test_join_attribute(env_async, users):
-    tmpl = env_async.from_string('''{{ users()|join(', ', 'username') }}''')
-    assert tmpl.render(users=users) == 'foo, bar'
+    tmpl = env_async.from_string("""{{ users()|join(', ', 'username') }}""")
+    assert tmpl.render(users=users) == "foo, bar"
 
 
-@mark_dualiter('items', lambda: [1, 2, 3, 4, 5])
+@mark_dualiter("items", lambda: [1, 2, 3, 4, 5])
 def test_simple_reject(env_async, items):
     tmpl = env_async.from_string('{{ items()|reject("odd")|join("|") }}')
-    assert tmpl.render(items=items) == '2|4'
+    assert tmpl.render(items=items) == "2|4"
 
 
-@mark_dualiter('items', lambda: [None, False, 0, 1, 2, 3, 4, 5])
+@mark_dualiter("items", lambda: [None, False, 0, 1, 2, 3, 4, 5])
 def test_bool_reject(env_async, items):
-    tmpl = env_async.from_string(
-        '{{ items()|reject|join("|") }}'
-    )
-    assert tmpl.render(items=items) == 'None|False|0'
+    tmpl = env_async.from_string('{{ items()|reject|join("|") }}')
+    assert tmpl.render(items=items) == "None|False|0"
 
 
-@mark_dualiter('items', lambda: [1, 2, 3, 4, 5])
+@mark_dualiter("items", lambda: [1, 2, 3, 4, 5])
 def test_simple_select(env_async, items):
     tmpl = env_async.from_string('{{ items()|select("odd")|join("|") }}')
-    assert tmpl.render(items=items) == '1|3|5'
+    assert tmpl.render(items=items) == "1|3|5"
 
 
-@mark_dualiter('items', lambda: [None, False, 0, 1, 2, 3, 4, 5])
+@mark_dualiter("items", lambda: [None, False, 0, 1, 2, 3, 4, 5])
 def test_bool_select(env_async, items):
-    tmpl = env_async.from_string(
-        '{{ items()|select|join("|") }}'
-    )
-    assert tmpl.render(items=items) == '1|2|3|4|5'
+    tmpl = env_async.from_string('{{ items()|select|join("|") }}')
+    assert tmpl.render(items=items) == "1|2|3|4|5"
 
 
 def make_users():
@@ -152,82 +157,82 @@ def make_users():
         def __init__(self, name, is_active):
             self.name = name
             self.is_active = is_active
+
     return [
-        User('john', True),
-        User('jane', True),
-        User('mike', False),
+        User("john", True),
+        User("jane", True),
+        User("mike", False),
     ]
 
 
-@mark_dualiter('users', make_users)
+@mark_dualiter("users", make_users)
 def test_simple_select_attr(env_async, users):
     tmpl = env_async.from_string(
-        '{{ users()|selectattr("is_active")|'
-        'map(attribute="name")|join("|") }}'
+        '{{ users()|selectattr("is_active")|map(attribute="name")|join("|") }}'
     )
-    assert tmpl.render(users=users) == 'john|jane'
+    assert tmpl.render(users=users) == "john|jane"
 
 
-@mark_dualiter('items', lambda: list('123'))
+@mark_dualiter("items", lambda: list("123"))
 def test_simple_map(env_async, items):
     tmpl = env_async.from_string('{{ items()|map("int")|sum }}')
-    assert tmpl.render(items=items) == '6'
+    assert tmpl.render(items=items) == "6"
 
 
 def test_map_sum(env_async):  # async map + async filter
     tmpl = env_async.from_string('{{ [[1,2], [3], [4,5,6]]|map("sum")|list }}')
-    assert tmpl.render() == '[3, 3, 15]'
+    assert tmpl.render() == "[3, 3, 15]"
 
 
-@mark_dualiter('users', make_users)
+@mark_dualiter("users", make_users)
 def test_attribute_map(env_async, users):
     tmpl = env_async.from_string('{{ users()|map(attribute="name")|join("|") }}')
-    assert tmpl.render(users=users) == 'john|jane|mike'
+    assert tmpl.render(users=users) == "john|jane|mike"
 
 
 def test_empty_map(env_async):
     tmpl = env_async.from_string('{{ none|map("upper")|list }}')
-    assert tmpl.render() == '[]'
+    assert tmpl.render() == "[]"
 
 
-@mark_dualiter('items', lambda: [1, 2, 3, 4, 5, 6])
+@mark_dualiter("items", lambda: [1, 2, 3, 4, 5, 6])
 def test_sum(env_async, items):
-    tmpl = env_async.from_string('''{{ items()|sum }}''')
-    assert tmpl.render(items=items) == '21'
+    tmpl = env_async.from_string("""{{ items()|sum }}""")
+    assert tmpl.render(items=items) == "21"
 
 
-@mark_dualiter('items', lambda: [
-    {'value': 23},
-    {'value': 1},
-    {'value': 18},
-])
+@mark_dualiter("items", lambda: [{"value": 23}, {"value": 1}, {"value": 18},])
 def test_sum_attributes(env_async, items):
-    tmpl = env_async.from_string('''{{ items()|sum('value') }}''')
+    tmpl = env_async.from_string("""{{ items()|sum('value') }}""")
     assert tmpl.render(items=items)
 
 
 def test_sum_attributes_nested(env_async):
-    tmpl = env_async.from_string('''{{ values|sum('real.value') }}''')
-    assert tmpl.render(values=[
-        {'real': {'value': 23}},
-        {'real': {'value': 1}},
-        {'real': {'value': 18}},
-    ]) == '42'
+    tmpl = env_async.from_string("""{{ values|sum('real.value') }}""")
+    assert (
+        tmpl.render(
+            values=[
+                {"real": {"value": 23}},
+                {"real": {"value": 1}},
+                {"real": {"value": 18}},
+            ]
+        )
+        == "42"
+    )
 
 
 def test_sum_attributes_tuple(env_async):
-    tmpl = env_async.from_string('''{{ values.items()|sum('1') }}''')
-    assert tmpl.render(values={
-        'foo': 23,
-        'bar': 1,
-        'baz': 18,
-    }) == '42'
+    tmpl = env_async.from_string("""{{ values.items()|sum('1') }}""")
+    assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18,}) == "42"
 
 
-@mark_dualiter('items', lambda: range(10))
+@mark_dualiter("items", lambda: range(10))
 def test_slice(env_async, items):
-    tmpl = env_async.from_string('{{ items()|slice(3)|list }}|'
-                                 '{{ items()|slice(3, "X")|list }}')
+    tmpl = env_async.from_string(
+        "{{ items()|slice(3)|list }}|" '{{ items()|slice(3, "X")|list }}'
+    )
     out = tmpl.render(items=items)
-    assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
-                   "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]")
+    assert out == (
+        "[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
+        "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]"
+    )
index a548ab2ea65728e5d75ac9d9d0e5d5b8cf27ec58..937c0fec20f3f929d838536d6c9eebe129b38c48 100644 (file)
@@ -20,19 +20,15 @@ from jinja2.exceptions import TemplateNotFound
 @pytest.fixture
 def env(package_loader):
     bytecode_cache = FileSystemBytecodeCache()
-    return Environment(
-        loader=package_loader,
-        bytecode_cache=bytecode_cache,
-    )
+    return Environment(loader=package_loader, bytecode_cache=bytecode_cache,)
 
 
 @pytest.mark.byte_code_cache
 class TestByteCodeCache(object):
-
     def test_simple(self, env):
-        tmpl = env.get_template('test.html')
-        assert tmpl.render().strip() == 'BAR'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
+        tmpl = env.get_template("test.html")
+        assert tmpl.render().strip() == "BAR"
+        pytest.raises(TemplateNotFound, env.get_template, "missing.html")
 
 
 class MockMemcached(object):
@@ -63,22 +59,22 @@ class TestMemcachedBytecodeCache(object):
         memcached = MockMemcached()
         m = MemcachedBytecodeCache(memcached)
 
-        b = Bucket(None, 'key', '')
-        b.code = 'code'
+        b = Bucket(None, "key", "")
+        b.code = "code"
         m.dump_bytecode(b)
-        assert memcached.key == 'jinja2/bytecode/key'
+        assert memcached.key == "jinja2/bytecode/key"
 
-        b = Bucket(None, 'key', '')
+        b = Bucket(None, "key", "")
         m.load_bytecode(b)
-        assert b.code == 'code'
+        assert b.code == "code"
 
     def test_exception(self):
         memcached = MockMemcached()
         memcached.get = memcached.get_side_effect
         memcached.set = memcached.set_side_effect
         m = MemcachedBytecodeCache(memcached)
-        b = Bucket(None, 'key', '')
-        b.code = 'code'
+        b = Bucket(None, "key", "")
+        b.code = "code"
 
         m.dump_bytecode(b)
         m.load_bytecode(b)
index 27981bea9aad44401643321d2d1ff2bb9599d579..deb016938fac2b9b13b2d653a1d53b2a8df1566e 100644 (file)
@@ -25,70 +25,89 @@ def env_trim():
 @pytest.mark.core_tags
 @pytest.mark.for_loop
 class TestForLoop(object):
-
     def test_simple(self, env):
-        tmpl = env.from_string('{% for item in seq %}{{ item }}{% endfor %}')
-        assert tmpl.render(seq=list(range(10))) == '0123456789'
+        tmpl = env.from_string("{% for item in seq %}{{ item }}{% endfor %}")
+        assert tmpl.render(seq=list(range(10))) == "0123456789"
 
     def test_else(self, env):
-        tmpl = env.from_string(
-            '{% for item in seq %}XXX{% else %}...{% endfor %}')
-        assert tmpl.render() == '...'
+        tmpl = env.from_string("{% for item in seq %}XXX{% else %}...{% endfor %}")
+        assert tmpl.render() == "..."
 
     def test_else_scoping_item(self, env):
-        tmpl = env.from_string(
-            '{% for item in [] %}{% else %}{{ item }}{% endfor %}')
-        assert tmpl.render(item=42) == '42'
+        tmpl = env.from_string("{% for item in [] %}{% else %}{{ item }}{% endfor %}")
+        assert tmpl.render(item=42) == "42"
 
     def test_empty_blocks(self, env):
-        tmpl = env.from_string('<{% for item in seq %}{% else %}{% endfor %}>')
-        assert tmpl.render() == '<>'
+        tmpl = env.from_string("<{% for item in seq %}{% else %}{% endfor %}>")
+        assert tmpl.render() == "<>"
 
     def test_context_vars(self, env):
         slist = [42, 24]
         for seq in [slist, iter(slist), reversed(slist), (_ for _ in slist)]:
-            tmpl = env.from_string('''{% for item in seq -%}
+            tmpl = env.from_string(
+                """{% for item in seq -%}
             {{ loop.index }}|{{ loop.index0 }}|{{ loop.revindex }}|{{
                 loop.revindex0 }}|{{ loop.first }}|{{ loop.last }}|{{
-               loop.length }}###{% endfor %}''')
-            one, two, _ = tmpl.render(seq=seq).split('###')
-            (one_index, one_index0, one_revindex, one_revindex0, one_first,
-             one_last, one_length) = one.split('|')
-            (two_index, two_index0, two_revindex, two_revindex0, two_first,
-             two_last, two_length) = two.split('|')
+               loop.length }}###{% endfor %}"""
+            )
+            one, two, _ = tmpl.render(seq=seq).split("###")
+            (
+                one_index,
+                one_index0,
+                one_revindex,
+                one_revindex0,
+                one_first,
+                one_last,
+                one_length,
+            ) = one.split("|")
+            (
+                two_index,
+                two_index0,
+                two_revindex,
+                two_revindex0,
+                two_first,
+                two_last,
+                two_length,
+            ) = two.split("|")
 
             assert int(one_index) == 1 and int(two_index) == 2
             assert int(one_index0) == 0 and int(two_index0) == 1
             assert int(one_revindex) == 2 and int(two_revindex) == 1
             assert int(one_revindex0) == 1 and int(two_revindex0) == 0
-            assert one_first == 'True' and two_first == 'False'
-            assert one_last == 'False' and two_last == 'True'
-            assert one_length == two_length == '2'
+            assert one_first == "True" and two_first == "False"
+            assert one_last == "False" and two_last == "True"
+            assert one_length == two_length == "2"
 
     def test_cycling(self, env):
-        tmpl = env.from_string('''{% for item in seq %}{{
+        tmpl = env.from_string(
+            """{% for item in seq %}{{
             loop.cycle('<1>', '<2>') }}{% endfor %}{%
-            for item in seq %}{{ loop.cycle(*through) }}{% endfor %}''')
-        output = tmpl.render(seq=list(range(4)), through=('<1>', '<2>'))
-        assert output == '<1><2>' * 4
+            for item in seq %}{{ loop.cycle(*through) }}{% endfor %}"""
+        )
+        output = tmpl.render(seq=list(range(4)), through=("<1>", "<2>"))
+        assert output == "<1><2>" * 4
 
     def test_lookaround(self, env):
-        tmpl = env.from_string('''{% for item in seq -%}
+        tmpl = env.from_string(
+            """{% for item in seq -%}
             {{ loop.previtem|default('x') }}-{{ item }}-{{
             loop.nextitem|default('x') }}|
-        {%- endfor %}''')
+        {%- endfor %}"""
+        )
         output = tmpl.render(seq=list(range(4)))
-        assert output == 'x-0-1|0-1-2|1-2-3|2-3-x|'
+        assert output == "x-0-1|0-1-2|1-2-3|2-3-x|"
 
     def test_changed(self, env):
-        tmpl = env.from_string('''{% for item in seq -%}
+        tmpl = env.from_string(
+            """{% for item in seq -%}
             {{ loop.changed(item) }},
-        {%- endfor %}''')
+        {%- endfor %}"""
+        )
         output = tmpl.render(seq=[None, None, 1, 2, 2, 3, 4, 4, 4])
-        assert output == 'True,False,True,True,False,True,True,False,False,'
+        assert output == "True,False,True,True,False,True,True,False,False,"
 
     def test_scope(self, env):
-        tmpl = env.from_string('{% for item in seq %}{% endfor %}{{ item }}')
+        tmpl = env.from_string("{% for item in seq %}{% endfor %}{{ item }}")
         output = tmpl.render(seq=list(range(10)))
         assert not output
 
@@ -96,115 +115,163 @@ class TestForLoop(object):
         def inner():
             for item in range(5):
                 yield item
-        tmpl = env.from_string('{% for item in iter %}{{ item }}{% endfor %}')
+
+        tmpl = env.from_string("{% for item in iter %}{{ item }}{% endfor %}")
         output = tmpl.render(iter=inner())
-        assert output == '01234'
+        assert output == "01234"
 
     def test_noniter(self, env):
-        tmpl = env.from_string('{% for item in none %}...{% endfor %}')
+        tmpl = env.from_string("{% for item in none %}...{% endfor %}")
         pytest.raises(TypeError, tmpl.render)
 
     def test_recursive(self, env):
-        tmpl = env.from_string('''{% for item in seq recursive -%}
+        tmpl = env.from_string(
+            """{% for item in seq recursive -%}
             [{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[1<[1][2]>][2<[1][2]>][3<[a]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[1<[1][2]>][2<[1][2]>][3<[a]>]"
+        )
 
     def test_recursive_lookaround(self, env):
-        tmpl = env.from_string('''{% for item in seq recursive -%}
+        tmpl = env.from_string(
+            """{% for item in seq recursive -%}
             [{{ loop.previtem.a if loop.previtem is defined else 'x' }}.{{
             item.a }}.{{ loop.nextitem.a if loop.nextitem is defined else 'x'
             }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[x.1.2<[x.1.2][1.2.x]>][1.2.3<[x.1.2][1.2.x]>][2.3.x<[x.a.x]>]"
+        )
 
     def test_recursive_depth0(self, env):
-        tmpl = env.from_string('''{% for item in seq recursive -%}
+        tmpl = env.from_string(
+            """{% for item in seq recursive -%}
             [{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[0:1<[1:1][1:2]>][0:2<[1:1][1:2]>][0:3<[1:a]>]"
+        )
 
     def test_recursive_depth(self, env):
-        tmpl = env.from_string('''{% for item in seq recursive -%}
+        tmpl = env.from_string(
+            """{% for item in seq recursive -%}
             [{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
-        {%- endfor %}''')
-        assert tmpl.render(seq=[
-            dict(a=1, b=[dict(a=1), dict(a=2)]),
-            dict(a=2, b=[dict(a=1), dict(a=2)]),
-            dict(a=3, b=[dict(a='a')])
-        ]) == '[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]'
+        {%- endfor %}"""
+        )
+        assert (
+            tmpl.render(
+                seq=[
+                    dict(a=1, b=[dict(a=1), dict(a=2)]),
+                    dict(a=2, b=[dict(a=1), dict(a=2)]),
+                    dict(a=3, b=[dict(a="a")]),
+                ]
+            )
+            == "[1:1<[2:1][2:2]>][1:2<[2:1][2:2]>][1:3<[2:a]>]"
+        )
 
     def test_looploop(self, env):
-        tmpl = env.from_string('''{% for row in table %}
+        tmpl = env.from_string(
+            """{% for row in table %}
             {%- set rowloop = loop -%}
             {% for cell in row -%}
                 [{{ rowloop.index }}|{{ loop.index }}]
             {%- endfor %}
-        {%- endfor %}''')
-        assert tmpl.render(table=['ab', 'cd']) == '[1|1][1|2][2|1][2|2]'
+        {%- endfor %}"""
+        )
+        assert tmpl.render(table=["ab", "cd"]) == "[1|1][1|2][2|1][2|2]"
 
     def test_reversed_bug(self, env):
-        tmpl = env.from_string('{% for i in items %}{{ i }}'
-                               '{% if not loop.last %}'
-                               ',{% endif %}{% endfor %}')
-        assert tmpl.render(items=reversed([3, 2, 1])) == '1,2,3'
+        tmpl = env.from_string(
+            "{% for i in items %}{{ i }}"
+            "{% if not loop.last %}"
+            ",{% endif %}{% endfor %}"
+        )
+        assert tmpl.render(items=reversed([3, 2, 1])) == "1,2,3"
 
     def test_loop_errors(self, env):
-        tmpl = env.from_string('''{% for item in [1] if loop.index
-                                      == 0 %}...{% endfor %}''')
+        tmpl = env.from_string(
+            """{% for item in [1] if loop.index
+                                      == 0 %}...{% endfor %}"""
+        )
         pytest.raises(UndefinedError, tmpl.render)
-        tmpl = env.from_string('''{% for item in [] %}...{% else
-            %}{{ loop }}{% endfor %}''')
-        assert tmpl.render() == ''
+        tmpl = env.from_string(
+            """{% for item in [] %}...{% else
+            %}{{ loop }}{% endfor %}"""
+        )
+        assert tmpl.render() == ""
 
     def test_loop_filter(self, env):
-        tmpl = env.from_string('{% for item in range(10) if item '
-                               'is even %}[{{ item }}]{% endfor %}')
-        assert tmpl.render() == '[0][2][4][6][8]'
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            "{% for item in range(10) if item is even %}[{{ item }}]{% endfor %}"
+        )
+        assert tmpl.render() == "[0][2][4][6][8]"
+        tmpl = env.from_string(
+            """
             {%- for item in range(10) if item is even %}[{{
-                loop.index }}:{{ item }}]{% endfor %}''')
-        assert tmpl.render() == '[1:0][2:2][3:4][4:6][5:8]'
+                loop.index }}:{{ item }}]{% endfor %}"""
+        )
+        assert tmpl.render() == "[1:0][2:2][3:4][4:6][5:8]"
 
     def test_loop_unassignable(self, env):
-        pytest.raises(TemplateSyntaxError, env.from_string,
-                      '{% for loop in seq %}...{% endfor %}')
+        pytest.raises(
+            TemplateSyntaxError, env.from_string, "{% for loop in seq %}...{% endfor %}"
+        )
 
     def test_scoped_special_var(self, env):
         t = env.from_string(
-            '{% for s in seq %}[{{ loop.first }}{% for c in s %}'
-            '|{{ loop.first }}{% endfor %}]{% endfor %}')
-        assert t.render(seq=('ab', 'cd')) \
-            == '[True|True|False][False|True|False]'
+            "{% for s in seq %}[{{ loop.first }}{% for c in s %}"
+            "|{{ loop.first }}{% endfor %}]{% endfor %}"
+        )
+        assert t.render(seq=("ab", "cd")) == "[True|True|False][False|True|False]"
 
     def test_scoped_loop_var(self, env):
-        t = env.from_string('{% for x in seq %}{{ loop.first }}'
-                            '{% for y in seq %}{% endfor %}{% endfor %}')
-        assert t.render(seq='ab') == 'TrueFalse'
-        t = env.from_string('{% for x in seq %}{% for y in seq %}'
-                            '{{ loop.first }}{% endfor %}{% endfor %}')
-        assert t.render(seq='ab') == 'TrueFalseTrueFalse'
+        t = env.from_string(
+            "{% for x in seq %}{{ loop.first }}"
+            "{% for y in seq %}{% endfor %}{% endfor %}"
+        )
+        assert t.render(seq="ab") == "TrueFalse"
+        t = env.from_string(
+            "{% for x in seq %}{% for y in seq %}"
+            "{{ loop.first }}{% endfor %}{% endfor %}"
+        )
+        assert t.render(seq="ab") == "TrueFalseTrueFalse"
 
     def test_recursive_empty_loop_iter(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- for item in foo recursive -%}{%- endfor -%}
-        ''')
-        assert t.render(dict(foo=[])) == ''
+        """
+        )
+        assert t.render(dict(foo=[])) == ""
 
     def test_call_in_loop(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- macro do_something() -%}
             [{{ caller() }}]
         {%- endmacro %}
@@ -214,150 +281,179 @@ class TestForLoop(object):
                 {{ i }}
             {%- endcall %}
         {%- endfor -%}
-        ''')
-        assert t.render() == '[1][2][3]'
+        """
+        )
+        assert t.render() == "[1][2][3]"
 
     def test_scoping_bug(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- for item in foo %}...{{ item }}...{% endfor %}
         {%- macro item(a) %}...{{ a }}...{% endmacro %}
         {{- item(2) -}}
-        ''')
-        assert t.render(foo=(1,)) == '...1......2...'
+        """
+        )
+        assert t.render(foo=(1,)) == "...1......2..."
 
     def test_unpacking(self, env):
-        tmpl = env.from_string('{% for a, b, c in [[1, 2, 3]] %}'
-                               '{{ a }}|{{ b }}|{{ c }}{% endfor %}')
-        assert tmpl.render() == '1|2|3'
+        tmpl = env.from_string(
+            "{% for a, b, c in [[1, 2, 3]] %}{{ a }}|{{ b }}|{{ c }}{% endfor %}"
+        )
+        assert tmpl.render() == "1|2|3"
 
     def test_intended_scoping_with_set(self, env):
-        tmpl = env.from_string('{% for item in seq %}{{ x }}'
-                               '{% set x = item %}{{ x }}{% endfor %}')
-        assert tmpl.render(x=0, seq=[1, 2, 3]) == '010203'
+        tmpl = env.from_string(
+            "{% for item in seq %}{{ x }}{% set x = item %}{{ x }}{% endfor %}"
+        )
+        assert tmpl.render(x=0, seq=[1, 2, 3]) == "010203"
 
-        tmpl = env.from_string('{% set x = 9 %}{% for item in seq %}{{ x }}'
-                               '{% set x = item %}{{ x }}{% endfor %}')
-        assert tmpl.render(x=0, seq=[1, 2, 3]) == '919293'
+        tmpl = env.from_string(
+            "{% set x = 9 %}{% for item in seq %}{{ x }}"
+            "{% set x = item %}{{ x }}{% endfor %}"
+        )
+        assert tmpl.render(x=0, seq=[1, 2, 3]) == "919293"
 
 
 @pytest.mark.core_tags
 @pytest.mark.if_condition
 class TestIfCondition(object):
-
     def test_simple(self, env):
-        tmpl = env.from_string('''{% if true %}...{% endif %}''')
-        assert tmpl.render() == '...'
+        tmpl = env.from_string("""{% if true %}...{% endif %}""")
+        assert tmpl.render() == "..."
 
     def test_elif(self, env):
-        tmpl = env.from_string('''{% if false %}XXX{% elif true
-            %}...{% else %}XXX{% endif %}''')
-        assert tmpl.render() == '...'
+        tmpl = env.from_string(
+            """{% if false %}XXX{% elif true
+            %}...{% else %}XXX{% endif %}"""
+        )
+        assert tmpl.render() == "..."
 
     def test_elif_deep(self, env):
-        elifs = '\n'.join('{{% elif a == {0} %}}{0}'.format(i)
-                          for i in range(1, 1000))
-        tmpl = env.from_string('{{% if a == 0 %}}0{0}{{% else %}}x{{% endif %}}'
-                               .format(elifs))
+        elifs = "\n".join("{{% elif a == {0} %}}{0}".format(i) for i in range(1, 1000))
+        tmpl = env.from_string(
+            "{{% if a == 0 %}}0{0}{{% else %}}x{{% endif %}}".format(elifs)
+        )
         for x in (0, 10, 999):
             assert tmpl.render(a=x).strip() == str(x)
-        assert tmpl.render(a=1000).strip() == 'x'
+        assert tmpl.render(a=1000).strip() == "x"
 
     def test_else(self, env):
-        tmpl = env.from_string('{% if false %}XXX{% else %}...{% endif %}')
-        assert tmpl.render() == '...'
+        tmpl = env.from_string("{% if false %}XXX{% else %}...{% endif %}")
+        assert tmpl.render() == "..."
 
     def test_empty(self, env):
-        tmpl = env.from_string('[{% if true %}{% else %}{% endif %}]')
-        assert tmpl.render() == '[]'
+        tmpl = env.from_string("[{% if true %}{% else %}{% endif %}]")
+        assert tmpl.render() == "[]"
 
     def test_complete(self, env):
-        tmpl = env.from_string('{% if a %}A{% elif b %}B{% elif c == d %}'
-                               'C{% else %}D{% endif %}')
-        assert tmpl.render(a=0, b=False, c=42, d=42.0) == 'C'
+        tmpl = env.from_string(
+            "{% if a %}A{% elif b %}B{% elif c == d %}C{% else %}D{% endif %}"
+        )
+        assert tmpl.render(a=0, b=False, c=42, d=42.0) == "C"
 
     def test_no_scope(self, env):
-        tmpl = env.from_string(
-            '{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}')
-        assert tmpl.render(a=True) == '1'
-        tmpl = env.from_string(
-            '{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}')
-        assert tmpl.render() == '1'
+        tmpl = env.from_string("{% if a %}{% set foo = 1 %}{% endif %}{{ foo }}")
+        assert tmpl.render(a=True) == "1"
+        tmpl = env.from_string("{% if true %}{% set foo = 1 %}{% endif %}{{ foo }}")
+        assert tmpl.render() == "1"
 
 
 @pytest.mark.core_tags
 @pytest.mark.macros
 class TestMacros(object):
     def test_simple(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% macro say_hello(name) %}Hello {{ name }}!{% endmacro %}
-{{ say_hello('Peter') }}''')
-        assert tmpl.render() == 'Hello Peter!'
+{{ say_hello('Peter') }}"""
+        )
+        assert tmpl.render() == "Hello Peter!"
 
     def test_scoping(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% macro level1(data1) %}
 {% macro level2(data2) %}{{ data1 }}|{{ data2 }}{% endmacro %}
 {{ level2('bar') }}{% endmacro %}
-{{ level1('foo') }}''')
-        assert tmpl.render() == 'foo|bar'
+{{ level1('foo') }}"""
+        )
+        assert tmpl.render() == "foo|bar"
 
     def test_arguments(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% macro m(a, b, c='c', d='d') %}{{ a }}|{{ b }}|{{ c }}|{{ d }}{% endmacro %}
-{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}''')
-        assert tmpl.render() == '||c|d|a||c|d|a|b|c|d|1|2|3|d'
+{{ m() }}|{{ m('a') }}|{{ m('a', 'b') }}|{{ m(1, 2, 3) }}"""
+        )
+        assert tmpl.render() == "||c|d|a||c|d|a|b|c|d|1|2|3|d"
 
     def test_arguments_defaults_nonsense(self, env_trim):
-        pytest.raises(TemplateSyntaxError, env_trim.from_string, '''\
-{% macro m(a, b=1, c) %}a={{ a }}, b={{ b }}, c={{ c }}{% endmacro %}''')
+        pytest.raises(
+            TemplateSyntaxError,
+            env_trim.from_string,
+            """\
+{% macro m(a, b=1, c) %}a={{ a }}, b={{ b }}, c={{ c }}{% endmacro %}""",
+        )
 
     def test_caller_defaults_nonsense(self, env_trim):
-        pytest.raises(TemplateSyntaxError, env_trim.from_string, '''\
+        pytest.raises(
+            TemplateSyntaxError,
+            env_trim.from_string,
+            """\
 {% macro a() %}{{ caller() }}{% endmacro %}
-{% call(x, y=1, z) a() %}{% endcall %}''')
+{% call(x, y=1, z) a() %}{% endcall %}""",
+        )
 
     def test_varargs(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% macro test() %}{{ varargs|join('|') }}{% endmacro %}\
-{{ test(1, 2, 3) }}''')
-        assert tmpl.render() == '1|2|3'
+{{ test(1, 2, 3) }}"""
+        )
+        assert tmpl.render() == "1|2|3"
 
     def test_simple_call(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% macro test() %}[[{{ caller() }}]]{% endmacro %}\
-{% call test() %}data{% endcall %}''')
-        assert tmpl.render() == '[[data]]'
+{% call test() %}data{% endcall %}"""
+        )
+        assert tmpl.render() == "[[data]]"
 
     def test_complex_call(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% macro test() %}[[{{ caller('data') }}]]{% endmacro %}\
-{% call(data) test() %}{{ data }}{% endcall %}''')
-        assert tmpl.render() == '[[data]]'
+{% call(data) test() %}{{ data }}{% endcall %}"""
+        )
+        assert tmpl.render() == "[[data]]"
 
     def test_caller_undefined(self, env_trim):
-        tmpl = env_trim.from_string('''\
+        tmpl = env_trim.from_string(
+            """\
 {% set caller = 42 %}\
 {% macro test() %}{{ caller is not defined }}{% endmacro %}\
-{{ test() }}''')
-        assert tmpl.render() == 'True'
+{{ test() }}"""
+        )
+        assert tmpl.render() == "True"
 
     def test_include(self, env_trim):
         env_trim = Environment(
-            loader=DictLoader({
-                'include': '{% macro test(foo) %}[{{ foo }}]{% endmacro %}'
-            })
+            loader=DictLoader(
+                {"include": "{% macro test(foo) %}[{{ foo }}]{% endmacro %}"}
+            )
         )
-        tmpl = env_trim.from_string(
-            '{% from "include" import test %}{{ test("foo") }}')
-        assert tmpl.render() == '[foo]'
+        tmpl = env_trim.from_string('{% from "include" import test %}{{ test("foo") }}')
+        assert tmpl.render() == "[foo]"
 
     def test_macro_api(self, env_trim):
         tmpl = env_trim.from_string(
-            '{% macro foo(a, b) %}{% endmacro %}'
-            '{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}'
-            '{% macro baz() %}{{ caller() }}{% endmacro %}')
-        assert tmpl.module.foo.arguments == ('a', 'b')
-        assert tmpl.module.foo.name == 'foo'
+            "{% macro foo(a, b) %}{% endmacro %}"
+            "{% macro bar() %}{{ varargs }}{{ kwargs }}{% endmacro %}"
+            "{% macro baz() %}{{ caller() }}{% endmacro %}"
+        )
+        assert tmpl.module.foo.arguments == ("a", "b")
+        assert tmpl.module.foo.name == "foo"
         assert not tmpl.module.foo.caller
         assert not tmpl.module.foo.catch_kwargs
         assert not tmpl.module.foo.catch_varargs
@@ -368,141 +464,160 @@ class TestMacros(object):
         assert tmpl.module.baz.caller
 
     def test_callself(self, env_trim):
-        tmpl = env_trim.from_string('{% macro foo(x) %}{{ x }}{% if x > 1 %}|'
-                                    '{{ foo(x - 1) }}{% endif %}{% endmacro %}'
-                                    '{{ foo(5) }}')
-        assert tmpl.render() == '5|4|3|2|1'
+        tmpl = env_trim.from_string(
+            "{% macro foo(x) %}{{ x }}{% if x > 1 %}|"
+            "{{ foo(x - 1) }}{% endif %}{% endmacro %}"
+            "{{ foo(5) }}"
+        )
+        assert tmpl.render() == "5|4|3|2|1"
 
     def test_macro_defaults_self_ref(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
             {%- set x = 42 %}
             {%- macro m(a, b=x, x=23) %}{{ a }}|{{ b }}|{{ x }}{% endmacro -%}
-        ''')
-        assert tmpl.module.m(1) == '1||23'
-        assert tmpl.module.m(1, 2) == '1|2|23'
-        assert tmpl.module.m(1, 2, 3) == '1|2|3'
-        assert tmpl.module.m(1, x=7) == '1|7|7'
+        """
+        )
+        assert tmpl.module.m(1) == "1||23"
+        assert tmpl.module.m(1, 2) == "1|2|23"
+        assert tmpl.module.m(1, 2, 3) == "1|2|3"
+        assert tmpl.module.m(1, x=7) == "1|7|7"
 
 
 @pytest.mark.core_tags
 @pytest.mark.set
 class TestSet(object):
-
     def test_normal(self, env_trim):
-        tmpl = env_trim.from_string('{% set foo = 1 %}{{ foo }}')
-        assert tmpl.render() == '1'
+        tmpl = env_trim.from_string("{% set foo = 1 %}{{ foo }}")
+        assert tmpl.render() == "1"
         assert tmpl.module.foo == 1
 
     def test_block(self, env_trim):
-        tmpl = env_trim.from_string('{% set foo %}42{% endset %}{{ foo }}')
-        assert tmpl.render() == '42'
-        assert tmpl.module.foo == u'42'
+        tmpl = env_trim.from_string("{% set foo %}42{% endset %}{{ foo }}")
+        assert tmpl.render() == "42"
+        assert tmpl.module.foo == u"42"
 
     def test_block_escaping(self):
         env = Environment(autoescape=True)
-        tmpl = env.from_string('{% set foo %}<em>{{ test }}</em>'
-                               '{% endset %}foo: {{ foo }}')
-        assert tmpl.render(test='<unsafe>') == 'foo: <em>&lt;unsafe&gt;</em>'
+        tmpl = env.from_string(
+            "{% set foo %}<em>{{ test }}</em>{% endset %}foo: {{ foo }}"
+        )
+        assert tmpl.render(test="<unsafe>") == "foo: <em>&lt;unsafe&gt;</em>"
 
     def test_set_invalid(self, env_trim):
-        pytest.raises(TemplateSyntaxError, env_trim.from_string,
-                      "{% set foo['bar'] = 1 %}")
-        tmpl = env_trim.from_string('{% set foo.bar = 1 %}')
+        pytest.raises(
+            TemplateSyntaxError, env_trim.from_string, "{% set foo['bar'] = 1 %}"
+        )
+        tmpl = env_trim.from_string("{% set foo.bar = 1 %}")
         exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, foo={})
-        assert 'non-namespace object' in exc_info.value.message
+        assert "non-namespace object" in exc_info.value.message
 
     def test_namespace_redefined(self, env_trim):
-        tmpl = env_trim.from_string('{% set ns = namespace() %}'
-                                    '{% set ns.bar = "hi" %}')
-        exc_info = pytest.raises(TemplateRuntimeError, tmpl.render,
-                                 namespace=dict)
-        assert 'non-namespace object' in exc_info.value.message
+        tmpl = env_trim.from_string(
+            "{% set ns = namespace() %}" '{% set ns.bar = "hi" %}'
+        )
+        exc_info = pytest.raises(TemplateRuntimeError, tmpl.render, namespace=dict)
+        assert "non-namespace object" in exc_info.value.message
 
     def test_namespace(self, env_trim):
-        tmpl = env_trim.from_string('{% set ns = namespace() %}'
-                                    '{% set ns.bar = "42" %}'
-                                    '{{ ns.bar }}')
-        assert tmpl.render() == '42'
+        tmpl = env_trim.from_string(
+            "{% set ns = namespace() %}" '{% set ns.bar = "42" %}' "{{ ns.bar }}"
+        )
+        assert tmpl.render() == "42"
 
     def test_namespace_block(self, env_trim):
-        tmpl = env_trim.from_string('{% set ns = namespace() %}'
-                                    '{% set ns.bar %}42{% endset %}'
-                                    '{{ ns.bar }}')
-        assert tmpl.render() == '42'
+        tmpl = env_trim.from_string(
+            "{% set ns = namespace() %}{% set ns.bar %}42{% endset %}{{ ns.bar }}"
+        )
+        assert tmpl.render() == "42"
 
     def test_init_namespace(self, env_trim):
-        tmpl = env_trim.from_string('{% set ns = namespace(d, self=37) %}'
-                                    '{% set ns.b = 42 %}'
-                                    '{{ ns.a }}|{{ ns.self }}|{{ ns.b }}')
-        assert tmpl.render(d={'a': 13}) == '13|37|42'
+        tmpl = env_trim.from_string(
+            "{% set ns = namespace(d, self=37) %}"
+            "{% set ns.b = 42 %}"
+            "{{ ns.a }}|{{ ns.self }}|{{ ns.b }}"
+        )
+        assert tmpl.render(d={"a": 13}) == "13|37|42"
 
     def test_namespace_loop(self, env_trim):
-        tmpl = env_trim.from_string('{% set ns = namespace(found=false) %}'
-                                    '{% for x in range(4) %}'
-                                    '{% if x == v %}'
-                                    '{% set ns.found = true %}'
-                                    '{% endif %}'
-                                    '{% endfor %}'
-                                    '{{ ns.found }}')
-        assert tmpl.render(v=3) == 'True'
-        assert tmpl.render(v=4) == 'False'
+        tmpl = env_trim.from_string(
+            "{% set ns = namespace(found=false) %}"
+            "{% for x in range(4) %}"
+            "{% if x == v %}"
+            "{% set ns.found = true %}"
+            "{% endif %}"
+            "{% endfor %}"
+            "{{ ns.found }}"
+        )
+        assert tmpl.render(v=3) == "True"
+        assert tmpl.render(v=4) == "False"
 
     def test_namespace_macro(self, env_trim):
-        tmpl = env_trim.from_string('{% set ns = namespace() %}'
-                                    '{% set ns.a = 13 %}'
-                                    '{% macro magic(x) %}'
-                                    '{% set x.b = 37 %}'
-                                    '{% endmacro %}'
-                                    '{{ magic(ns) }}'
-                                    '{{ ns.a }}|{{ ns.b }}')
-        assert tmpl.render() == '13|37'
+        tmpl = env_trim.from_string(
+            "{% set ns = namespace() %}"
+            "{% set ns.a = 13 %}"
+            "{% macro magic(x) %}"
+            "{% set x.b = 37 %}"
+            "{% endmacro %}"
+            "{{ magic(ns) }}"
+            "{{ ns.a }}|{{ ns.b }}"
+        )
+        assert tmpl.render() == "13|37"
 
     def test_block_escaping_filtered(self):
         env = Environment(autoescape=True)
-        tmpl = env.from_string('{% set foo | trim %}<em>{{ test }}</em>    '
-                               '{% endset %}foo: {{ foo }}')
-        assert tmpl.render(test='<unsafe>') == 'foo: <em>&lt;unsafe&gt;</em>'
+        tmpl = env.from_string(
+            "{% set foo | trim %}<em>{{ test }}</em>    {% endset %}foo: {{ foo }}"
+        )
+        assert tmpl.render(test="<unsafe>") == "foo: <em>&lt;unsafe&gt;</em>"
 
     def test_block_filtered(self, env_trim):
         tmpl = env_trim.from_string(
-            '{% set foo | trim | length | string %} 42    {% endset %}'
-            '{{ foo }}')
-        assert tmpl.render() == '2'
-        assert tmpl.module.foo == u'2'
+            "{% set foo | trim | length | string %} 42    {% endset %}{{ foo }}"
+        )
+        assert tmpl.render() == "2"
+        assert tmpl.module.foo == u"2"
 
     def test_block_filtered_set(self, env_trim):
         def _myfilter(val, arg):
-            assert arg == ' xxx '
+            assert arg == " xxx "
             return val
-        env_trim.filters['myfilter'] = _myfilter
+
+        env_trim.filters["myfilter"] = _myfilter
         tmpl = env_trim.from_string(
             '{% set a = " xxx " %}'
-            '{% set foo | myfilter(a) | trim | length | string %}'
+            "{% set foo | myfilter(a) | trim | length | string %}"
             ' {% set b = " yy " %} 42 {{ a }}{{ b }}   '
-            '{% endset %}'
-            '{{ foo }}')
-        assert tmpl.render() == '11'
-        assert tmpl.module.foo == u'11'
+            "{% endset %}"
+            "{{ foo }}"
+        )
+        assert tmpl.render() == "11"
+        assert tmpl.module.foo == u"11"
 
 
 @pytest.mark.core_tags
 @pytest.mark.with_
 class TestWith(object):
-
     def test_with(self, env):
-        tmpl = env.from_string('''\
+        tmpl = env.from_string(
+            """\
         {% with a=42, b=23 -%}
             {{ a }} = {{ b }}
         {% endwith -%}
             {{ a }} = {{ b }}\
-        ''')
-        assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] \
-            == ['42 = 23', '1 = 2']
+        """
+        )
+        assert [x.strip() for x in tmpl.render(a=1, b=2).splitlines()] == [
+            "42 = 23",
+            "1 = 2",
+        ]
 
     def test_with_argument_scoping(self, env):
-        tmpl = env.from_string('''\
+        tmpl = env.from_string(
+            """\
         {%- with a=1, b=2, c=b, d=e, e=5 -%}
             {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
         {%- endwith -%}
-        ''')
-        assert tmpl.render(b=3, e=4) == '1|2|3|4|5'
+        """
+        )
+        assert tmpl.render(b=3, e=4) == "1|2|3|4|5"
index 78583deb51407f141534b1f78a8e4d5434cddff3..e19a540e13cf22a4042cf2da4c0a49e7a468caf6 100644 (file)
@@ -23,55 +23,66 @@ from jinja2 import TemplateSyntaxError
 
 @pytest.fixture
 def fs_env(filesystem_loader):
-    '''returns a new environment.
-    '''
+    """returns a new environment."""
     return Environment(loader=filesystem_loader)
 
 
 @pytest.mark.debug
 class TestDebug(object):
-
     def assert_traceback_matches(self, callback, expected_tb):
         try:
             callback()
-        except Exception as e:
+        except Exception:
             tb = format_exception(*sys.exc_info())
-            if re.search(expected_tb.strip(), ''.join(tb)) is None:
-                assert False, ('Traceback did not match:\n\n%s\nexpected:\n%s' %
-                               (''.join(tb), expected_tb))
+            if re.search(expected_tb.strip(), "".join(tb)) is None:
+                assert False, "Traceback did not match:\n\n%s\nexpected:\n%s" % (
+                    "".join(tb),
+                    expected_tb,
+                )
         else:
-            assert False, 'Expected exception'
+            assert False, "Expected exception"
 
     def test_runtime_error(self, fs_env):
         def test():
             tmpl.render(fail=lambda: 1 / 0)
-        tmpl = fs_env.get_template('broken.html')
-        self.assert_traceback_matches(test, r'''
+
+        tmpl = fs_env.get_template("broken.html")
+        self.assert_traceback_matches(
+            test,
+            r"""
   File ".*?broken.html", line 2, in (top-level template code|<module>)
     \{\{ fail\(\) \}\}
   File ".*debug?.pyc?", line \d+, in <lambda>
     tmpl\.render\(fail=lambda: 1 / 0\)
 ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
-''')
+""",
+        )
 
     def test_syntax_error(self, fs_env):
         # The trailing .*? is for PyPy 2 and 3, which don't seem to
         # clear the exception's original traceback, leaving the syntax
         # error in the middle of other compiler frames.
-        self.assert_traceback_matches(lambda: fs_env.get_template('syntaxerror.html'), r'''(?sm)
+        self.assert_traceback_matches(
+            lambda: fs_env.get_template("syntaxerror.html"),
+            r"""(?sm)
   File ".*?syntaxerror.html", line 4, in (template|<module>)
     \{% endif %\}.*?
 (jinja2\.exceptions\.)?TemplateSyntaxError: Encountered unknown tag 'endif'. Jinja was looking for the following tags: 'endfor' or 'else'. The innermost block that needs to be closed is 'for'.
-    ''')
+    """,
+        )
 
     def test_regular_syntax_error(self, fs_env):
         def test():
-            raise TemplateSyntaxError('wtf', 42)
-        self.assert_traceback_matches(test, r'''
+            raise TemplateSyntaxError("wtf", 42)
+
+        self.assert_traceback_matches(
+            test,
+            r"""
   File ".*debug.pyc?", line \d+, in test
-    raise TemplateSyntaxError\('wtf', 42\)
+    raise TemplateSyntaxError\("wtf", 42\)
 (jinja2\.exceptions\.)?TemplateSyntaxError: wtf
-  line 42''')
+  line 42""",
+        )
 
     def test_pickleable_syntax_error(self, fs_env):
         original = TemplateSyntaxError("bad template", 42, "test", "test.txt")
@@ -80,12 +91,14 @@ ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
         assert original.name == unpickled.name
 
     def test_include_syntax_error_source(self, filesystem_loader):
-        e = Environment(loader=ChoiceLoader(
-            [
-                filesystem_loader,
-                DictLoader({"inc": "a\n{% include 'syntaxerror.html' %}\nb"}),
-            ]
-        ))
+        e = Environment(
+            loader=ChoiceLoader(
+                [
+                    filesystem_loader,
+                    DictLoader({"inc": "a\n{% include 'syntaxerror.html' %}\nb"}),
+                ]
+            )
+        )
         t = e.get_template("inc")
 
         with pytest.raises(TemplateSyntaxError) as exc_info:
@@ -96,16 +109,19 @@ ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
     def test_local_extraction(self):
         from jinja2.debug import get_template_locals
         from jinja2.runtime import missing
-        locals = get_template_locals({
-            'l_0_foo': 42,
-            'l_1_foo': 23,
-            'l_2_foo': 13,
-            'l_0_bar': 99,
-            'l_1_bar': missing,
-            'l_0_baz': missing,
-        })
-        assert locals == {'foo': 13, 'bar': 99}
+
+        locals = get_template_locals(
+            {
+                "l_0_foo": 42,
+                "l_1_foo": 23,
+                "l_2_foo": 13,
+                "l_0_bar": 99,
+                "l_1_bar": missing,
+                "l_0_baz": missing,
+            }
+        )
+        assert locals == {"foo": 13, "bar": 99}
 
     def test_get_corresponding_lineno_traceback(self, fs_env):
-        tmpl = fs_env.get_template('test.html')
+        tmpl = fs_env.get_template("test.html")
         assert tmpl.get_corresponding_lineno(1) == 1
index 6e8ab140e03bad9ac4de73c64e8a27fa47337932..0a9b648fb424812f6d228a8d3e7ac5cd082c9895 100644 (file)
@@ -26,113 +26,112 @@ from jinja2.lexer import Token
 
 importable_object = 23
 
-_gettext_re = re.compile(r'_\((.*?)\)', re.DOTALL)
+_gettext_re = re.compile(r"_\((.*?)\)", re.DOTALL)
 
 
 i18n_templates = {
-    'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
-                   '{% block body %}{% endblock %}',
-    'child.html': '{% extends "master.html" %}{% block body %}'
-                  '{% trans %}watch out{% endtrans %}{% endblock %}',
-    'plural.html': '{% trans user_count %}One user online{% pluralize %}'
-                   '{{ user_count }} users online{% endtrans %}',
-    'plural2.html': '{% trans user_count=get_user_count() %}{{ user_count }}s'
-                    '{% pluralize %}{{ user_count }}p{% endtrans %}',
-    'stringformat.html': '{{ _("User: %(num)s")|format(num=user_count) }}'
+    "master.html": '<title>{{ page_title|default(_("missing")) }}</title>'
+    "{% block body %}{% endblock %}",
+    "child.html": '{% extends "master.html" %}{% block body %}'
+    "{% trans %}watch out{% endtrans %}{% endblock %}",
+    "plural.html": "{% trans user_count %}One user online{% pluralize %}"
+    "{{ user_count }} users online{% endtrans %}",
+    "plural2.html": "{% trans user_count=get_user_count() %}{{ user_count }}s"
+    "{% pluralize %}{{ user_count }}p{% endtrans %}",
+    "stringformat.html": '{{ _("User: %(num)s")|format(num=user_count) }}',
 }
 
 newstyle_i18n_templates = {
-    'master.html': '<title>{{ page_title|default(_("missing")) }}</title>'
-                   '{% block body %}{% endblock %}',
-    'child.html': '{% extends "master.html" %}{% block body %}'
-                  '{% trans %}watch out{% endtrans %}{% endblock %}',
-    'plural.html': '{% trans user_count %}One user online{% pluralize %}'
-                   '{{ user_count }} users online{% endtrans %}',
-    'stringformat.html': '{{ _("User: %(num)s", num=user_count) }}',
-    'ngettext.html': '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}',
-    'ngettext_long.html': '{% trans num=apples %}{{ num }} apple{% pluralize %}'
-                          '{{ num }} apples{% endtrans %}',
-    'transvars1.html': '{% trans %}User: {{ num }}{% endtrans %}',
-    'transvars2.html': '{% trans num=count %}User: {{ num }}{% endtrans %}',
-    'transvars3.html': '{% trans count=num %}User: {{ count }}{% endtrans %}',
-    'novars.html': '{% trans %}%(hello)s{% endtrans %}',
-    'vars.html': '{% trans %}{{ foo }}%(foo)s{% endtrans %}',
-    'explicitvars.html': '{% trans foo="42" %}%(foo)s{% endtrans %}'
+    "master.html": '<title>{{ page_title|default(_("missing")) }}</title>'
+    "{% block body %}{% endblock %}",
+    "child.html": '{% extends "master.html" %}{% block body %}'
+    "{% trans %}watch out{% endtrans %}{% endblock %}",
+    "plural.html": "{% trans user_count %}One user online{% pluralize %}"
+    "{{ user_count }} users online{% endtrans %}",
+    "stringformat.html": '{{ _("User: %(num)s", num=user_count) }}',
+    "ngettext.html": '{{ ngettext("%(num)s apple", "%(num)s apples", apples) }}',
+    "ngettext_long.html": "{% trans num=apples %}{{ num }} apple{% pluralize %}"
+    "{{ num }} apples{% endtrans %}",
+    "transvars1.html": "{% trans %}User: {{ num }}{% endtrans %}",
+    "transvars2.html": "{% trans num=count %}User: {{ num }}{% endtrans %}",
+    "transvars3.html": "{% trans count=num %}User: {{ count }}{% endtrans %}",
+    "novars.html": "{% trans %}%(hello)s{% endtrans %}",
+    "vars.html": "{% trans %}{{ foo }}%(foo)s{% endtrans %}",
+    "explicitvars.html": '{% trans foo="42" %}%(foo)s{% endtrans %}',
 }
 
 
 languages = {
-    'de': {
-        'missing':                      u'fehlend',
-        'watch out':                    u'pass auf',
-        'One user online':              u'Ein Benutzer online',
-        '%(user_count)s users online':  u'%(user_count)s Benutzer online',
-        'User: %(num)s':                u'Benutzer: %(num)s',
-        'User: %(count)s':              u'Benutzer: %(count)s',
-        '%(num)s apple':                u'%(num)s Apfel',
-        '%(num)s apples':               u'%(num)s Äpfel'
+    "de": {
+        "missing": u"fehlend",
+        "watch out": u"pass auf",
+        "One user online": u"Ein Benutzer online",
+        "%(user_count)s users online": u"%(user_count)s Benutzer online",
+        "User: %(num)s": u"Benutzer: %(num)s",
+        "User: %(count)s": u"Benutzer: %(count)s",
+        "%(num)s apple": u"%(num)s Apfel",
+        "%(num)s apples": u"%(num)s Äpfel",
     }
 }
 
 
 @contextfunction
 def gettext(context, string):
-    language = context.get('LANGUAGE', 'en')
+    language = context.get("LANGUAGE", "en")
     return languages.get(language, {}).get(string, string)
 
 
 @contextfunction
 def ngettext(context, s, p, n):
-    language = context.get('LANGUAGE', 'en')
+    language = context.get("LANGUAGE", "en")
     if n != 1:
         return languages.get(language, {}).get(p, p)
     return languages.get(language, {}).get(s, s)
 
 
 i18n_env = Environment(
-    loader=DictLoader(i18n_templates),
-    extensions=['jinja2.ext.i18n']
+    loader=DictLoader(i18n_templates), extensions=["jinja2.ext.i18n"]
+)
+i18n_env.globals.update({"_": gettext, "gettext": gettext, "ngettext": ngettext})
+i18n_env_trimmed = Environment(extensions=["jinja2.ext.i18n"])
+i18n_env_trimmed.policies["ext.i18n.trimmed"] = True
+i18n_env_trimmed.globals.update(
+    {"_": gettext, "gettext": gettext, "ngettext": ngettext}
 )
-i18n_env.globals.update({
-    '_':            gettext,
-    'gettext':      gettext,
-    'ngettext':     ngettext
-})
-i18n_env_trimmed = Environment(extensions=['jinja2.ext.i18n'])
-i18n_env_trimmed.policies['ext.i18n.trimmed'] = True
-i18n_env_trimmed.globals.update({
-    '_':            gettext,
-    'gettext':      gettext,
-    'ngettext':     ngettext
-})
 
 newstyle_i18n_env = Environment(
-    loader=DictLoader(newstyle_i18n_templates),
-    extensions=['jinja2.ext.i18n']
+    loader=DictLoader(newstyle_i18n_templates), extensions=["jinja2.ext.i18n"]
 )
 newstyle_i18n_env.install_gettext_callables(gettext, ngettext, newstyle=True)
 
 
 class ExampleExtension(Extension):
-    tags = set(['test'])
+    tags = set(["test"])
     ext_attr = 42
     context_reference_node_cls = nodes.ContextReference
 
     def parse(self, parser):
-        return nodes.Output([self.call_method('_dump', [
-            nodes.EnvironmentAttribute('sandboxed'),
-            self.attr('ext_attr'),
-            nodes.ImportedName(__name__ + '.importable_object'),
-            self.context_reference_node_cls()
-        ])]).set_lineno(next(parser.stream).lineno)
+        return nodes.Output(
+            [
+                self.call_method(
+                    "_dump",
+                    [
+                        nodes.EnvironmentAttribute("sandboxed"),
+                        self.attr("ext_attr"),
+                        nodes.ImportedName(__name__ + ".importable_object"),
+                        self.context_reference_node_cls(),
+                    ],
+                )
+            ]
+        ).set_lineno(next(parser.stream).lineno)
 
     def _dump(self, sandboxed, ext_attr, imported_object, context):
-        return '%s|%s|%s|%s|%s' % (
+        return "%s|%s|%s|%s|%s" % (
             sandboxed,
             ext_attr,
             imported_object,
             context.blocks,
-            context.get('test_var')
+            context.get("test_var"),
         )
 
 
@@ -141,16 +140,14 @@ class DerivedExampleExtension(ExampleExtension):
 
 
 class PreprocessorExtension(Extension):
-
     def preprocess(self, source, name, filename=None):
-        return source.replace('[[TEST]]', '({{ foo }})')
+        return source.replace("[[TEST]]", "({{ foo }})")
 
 
 class StreamFilterExtension(Extension):
-
     def filter_stream(self, stream):
         for token in stream:
-            if token.type == 'data':
+            if token.type == "data":
                 for t in self.interpolate(token):
                     yield t
             else:
@@ -164,75 +161,80 @@ class StreamFilterExtension(Extension):
             match = _gettext_re.search(token.value, pos)
             if match is None:
                 break
-            value = token.value[pos:match.start()]
+            value = token.value[pos : match.start()]
             if value:
-                yield Token(lineno, 'data', value)
+                yield Token(lineno, "data", value)
             lineno += count_newlines(token.value)
-            yield Token(lineno, 'variable_begin', None)
-            yield Token(lineno, 'name', 'gettext')
-            yield Token(lineno, 'lparen', None)
-            yield Token(lineno, 'string', match.group(1))
-            yield Token(lineno, 'rparen', None)
-            yield Token(lineno, 'variable_end', None)
+            yield Token(lineno, "variable_begin", None)
+            yield Token(lineno, "name", "gettext")
+            yield Token(lineno, "lparen", None)
+            yield Token(lineno, "string", match.group(1))
+            yield Token(lineno, "rparen", None)
+            yield Token(lineno, "variable_end", None)
             pos = match.end()
         if pos < end:
-            yield Token(lineno, 'data', token.value[pos:])
+            yield Token(lineno, "data", token.value[pos:])
 
 
 @pytest.mark.ext
 class TestExtensions(object):
-
     def test_extend_late(self):
         env = Environment()
-        env.add_extension('jinja2.ext.autoescape')
-        t = env.from_string(
-            '{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
-        assert t.render() == '&lt;test&gt;'
+        env.add_extension("jinja2.ext.autoescape")
+        t = env.from_string('{% autoescape true %}{{ "<test>" }}{% endautoescape %}')
+        assert t.render() == "&lt;test&gt;"
 
     def test_loop_controls(self):
-        env = Environment(extensions=['jinja2.ext.loopcontrols'])
+        env = Environment(extensions=["jinja2.ext.loopcontrols"])
 
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
             {%- for item in [1, 2, 3, 4] %}
                 {%- if item % 2 == 0 %}{% continue %}{% endif -%}
                 {{ item }}
-            {%- endfor %}''')
-        assert tmpl.render() == '13'
+            {%- endfor %}"""
+        )
+        assert tmpl.render() == "13"
 
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
             {%- for item in [1, 2, 3, 4] %}
                 {%- if item > 2 %}{% break %}{% endif -%}
                 {{ item }}
-            {%- endfor %}''')
-        assert tmpl.render() == '12'
+            {%- endfor %}"""
+        )
+        assert tmpl.render() == "12"
 
     def test_do(self):
-        env = Environment(extensions=['jinja2.ext.do'])
-        tmpl = env.from_string('''
+        env = Environment(extensions=["jinja2.ext.do"])
+        tmpl = env.from_string(
+            """
             {%- set items = [] %}
             {%- for char in "foo" %}
                 {%- do items.append(loop.index0 ~ char) %}
-            {%- endfor %}{{ items|join(', ') }}''')
-        assert tmpl.render() == '0f, 1o, 2o'
+            {%- endfor %}{{ items|join(', ') }}"""
+        )
+        assert tmpl.render() == "0f, 1o, 2o"
 
     def test_extension_nodes(self):
         env = Environment(extensions=[ExampleExtension])
-        tmpl = env.from_string('{% test %}')
-        assert tmpl.render() == 'False|42|23|{}|None'
+        tmpl = env.from_string("{% test %}")
+        assert tmpl.render() == "False|42|23|{}|None"
 
     def test_contextreference_node_passes_context(self):
         env = Environment(extensions=[ExampleExtension])
         tmpl = env.from_string('{% set test_var="test_content" %}{% test %}')
-        assert tmpl.render() == 'False|42|23|{}|test_content'
+        assert tmpl.render() == "False|42|23|{}|test_content"
 
     def test_contextreference_node_can_pass_locals(self):
         env = Environment(extensions=[DerivedExampleExtension])
         tmpl = env.from_string(
-            '{% for test_var in ["test_content"] %}{% test %}{% endfor %}')
-        assert tmpl.render() == 'False|42|23|{}|test_content'
+            '{% for test_var in ["test_content"] %}{% test %}{% endfor %}'
+        )
+        assert tmpl.render() == "False|42|23|{}|test_content"
 
     def test_identifier(self):
-        assert ExampleExtension.identifier == __name__ + '.ExampleExtension'
+        assert ExampleExtension.identifier == __name__ + ".ExampleExtension"
 
     def test_rebinding(self):
         original = Environment(extensions=[ExampleExtension])
@@ -243,15 +245,15 @@ class TestExtensions(object):
 
     def test_preprocessor_extension(self):
         env = Environment(extensions=[PreprocessorExtension])
-        tmpl = env.from_string('{[[TEST]]}')
-        assert tmpl.render(foo=42) == '{(42)}'
+        tmpl = env.from_string("{[[TEST]]}")
+        assert tmpl.render(foo=42) == "{(42)}"
 
     def test_streamfilter_extension(self):
         env = Environment(extensions=[StreamFilterExtension])
-        env.globals['gettext'] = lambda x: x.upper()
-        tmpl = env.from_string('Foo _(bar) Baz')
+        env.globals["gettext"] = lambda x: x.upper()
+        tmpl = env.from_string("Foo _(bar) Baz")
         out = tmpl.render()
-        assert out == 'Foo BAR Baz'
+        assert out == "Foo BAR Baz"
 
     def test_extension_ordering(self):
         class T1(Extension):
@@ -259,14 +261,15 @@ class TestExtensions(object):
 
         class T2(Extension):
             priority = 2
+
         env = Environment(extensions=[T1, T2])
         ext = list(env.iter_extensions())
         assert ext[0].__class__ is T1
         assert ext[1].__class__ is T2
 
     def test_debug(self):
-        env = Environment(extensions=['jinja2.ext.debug'])
-        t = env.from_string('Hello\n{% debug %}\nGoodbye')
+        env = Environment(extensions=["jinja2.ext.debug"])
+        t = env.from_string("Hello\n{% debug %}\nGoodbye")
         out = t.render()
 
         for value in ("context", "cycler", "filters", "abs", "tests", "!="):
@@ -275,304 +278,346 @@ class TestExtensions(object):
 
 @pytest.mark.ext
 class TestInternationalization(object):
-
     def test_trans(self):
-        tmpl = i18n_env.get_template('child.html')
-        assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
+        tmpl = i18n_env.get_template("child.html")
+        assert tmpl.render(LANGUAGE="de") == "<title>fehlend</title>pass auf"
 
     def test_trans_plural(self):
-        tmpl = i18n_env.get_template('plural.html')
-        assert tmpl.render(LANGUAGE='de', user_count=1) \
-            == 'Ein Benutzer online'
-        assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
+        tmpl = i18n_env.get_template("plural.html")
+        assert tmpl.render(LANGUAGE="de", user_count=1) == "Ein Benutzer online"
+        assert tmpl.render(LANGUAGE="de", user_count=2) == "2 Benutzer online"
 
     def test_trans_plural_with_functions(self):
-        tmpl = i18n_env.get_template('plural2.html')
+        tmpl = i18n_env.get_template("plural2.html")
 
         def get_user_count():
             get_user_count.called += 1
             return 1
+
         get_user_count.called = 0
-        assert tmpl.render(LANGUAGE='de', get_user_count=get_user_count) \
-            == '1s'
+        assert tmpl.render(LANGUAGE="de", get_user_count=get_user_count) == "1s"
         assert get_user_count.called == 1
 
     def test_complex_plural(self):
         tmpl = i18n_env.from_string(
-            '{% trans foo=42, count=2 %}{{ count }} item{% '
-            'pluralize count %}{{ count }} items{% endtrans %}')
-        assert tmpl.render() == '2 items'
-        pytest.raises(TemplateAssertionError, i18n_env.from_string,
-                      '{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
+            "{% trans foo=42, count=2 %}{{ count }} item{% "
+            "pluralize count %}{{ count }} items{% endtrans %}"
+        )
+        assert tmpl.render() == "2 items"
+        pytest.raises(
+            TemplateAssertionError,
+            i18n_env.from_string,
+            "{% trans foo %}...{% pluralize bar %}...{% endtrans %}",
+        )
 
     def test_trans_stringformatting(self):
-        tmpl = i18n_env.get_template('stringformat.html')
-        assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
+        tmpl = i18n_env.get_template("stringformat.html")
+        assert tmpl.render(LANGUAGE="de", user_count=5) == "Benutzer: 5"
 
     def test_trimmed(self):
         tmpl = i18n_env.from_string(
-            '{%- trans trimmed %}  hello\n  world  {% endtrans -%}')
-        assert tmpl.render() == 'hello world'
+            "{%- trans trimmed %}  hello\n  world  {% endtrans -%}"
+        )
+        assert tmpl.render() == "hello world"
 
     def test_trimmed_policy(self):
-        s = '{%- trans %}  hello\n  world  {% endtrans -%}'
+        s = "{%- trans %}  hello\n  world  {% endtrans -%}"
         tmpl = i18n_env.from_string(s)
         trimmed_tmpl = i18n_env_trimmed.from_string(s)
-        assert tmpl.render() == '  hello\n  world  '
-        assert trimmed_tmpl.render() == 'hello world'
+        assert tmpl.render() == "  hello\n  world  "
+        assert trimmed_tmpl.render() == "hello world"
 
     def test_trimmed_policy_override(self):
         tmpl = i18n_env_trimmed.from_string(
-            '{%- trans notrimmed %}  hello\n  world  {% endtrans -%}')
-        assert tmpl.render() == '  hello\n  world  '
+            "{%- trans notrimmed %}  hello\n  world  {% endtrans -%}"
+        )
+        assert tmpl.render() == "  hello\n  world  "
 
     def test_trimmed_vars(self):
         tmpl = i18n_env.from_string(
-            '{%- trans trimmed x="world" %}  hello\n  {{ x }} {% endtrans -%}')
-        assert tmpl.render() == 'hello world'
+            '{%- trans trimmed x="world" %}  hello\n  {{ x }} {% endtrans -%}'
+        )
+        assert tmpl.render() == "hello world"
 
     def test_trimmed_varname_trimmed(self):
         # unlikely variable name, but when used as a variable
         # it should not enable trimming
         tmpl = i18n_env.from_string(
-            '{%- trans trimmed = "world" %}  hello\n  {{ trimmed }}  '
-            '{% endtrans -%}')
-        assert tmpl.render() == '  hello\n  world  '
+            '{%- trans trimmed = "world" %}  hello\n  {{ trimmed }}  ' "{% endtrans -%}"
+        )
+        assert tmpl.render() == "  hello\n  world  "
 
     def test_extract(self):
         from jinja2.ext import babel_extract
-        source = BytesIO('''
+
+        source = BytesIO(
+            """
         {{ gettext('Hello World') }}
         {% trans %}Hello World{% endtrans %}
         {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
-        '''.encode('ascii'))  # make python 3 happy
-        assert list(babel_extract(source,
-                                  ('gettext', 'ngettext', '_'), [], {})) == [
-            (2, 'gettext', u'Hello World', []),
-            (3, 'gettext', u'Hello World', []),
-            (4, 'ngettext', (u'%(users)s user', u'%(users)s users', None), [])
+        """.encode(
+                "ascii"
+            )
+        )  # make python 3 happy
+        assert list(babel_extract(source, ("gettext", "ngettext", "_"), [], {})) == [
+            (2, "gettext", u"Hello World", []),
+            (3, "gettext", u"Hello World", []),
+            (4, "ngettext", (u"%(users)s user", u"%(users)s users", None), []),
         ]
 
     def test_extract_trimmed(self):
         from jinja2.ext import babel_extract
-        source = BytesIO('''
+
+        source = BytesIO(
+            """
         {{ gettext(' Hello  \n  World') }}
         {% trans trimmed %} Hello  \n  World{% endtrans %}
         {% trans trimmed %}{{ users }} \n user
         {%- pluralize %}{{ users }} \n users{% endtrans %}
-        '''.encode('ascii'))  # make python 3 happy
-        assert list(babel_extract(source,
-                                  ('gettext', 'ngettext', '_'), [], {})) == [
-            (2, 'gettext', u' Hello  \n  World', []),
-            (4, 'gettext', u'Hello World', []),
-            (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), [])
+        """.encode(
+                "ascii"
+            )
+        )  # make python 3 happy
+        assert list(babel_extract(source, ("gettext", "ngettext", "_"), [], {})) == [
+            (2, "gettext", u" Hello  \n  World", []),
+            (4, "gettext", u"Hello World", []),
+            (6, "ngettext", (u"%(users)s user", u"%(users)s users", None), []),
         ]
 
     def test_extract_trimmed_option(self):
         from jinja2.ext import babel_extract
-        source = BytesIO('''
+
+        source = BytesIO(
+            """
         {{ gettext(' Hello  \n  World') }}
         {% trans %} Hello  \n  World{% endtrans %}
         {% trans %}{{ users }} \n user
         {%- pluralize %}{{ users }} \n users{% endtrans %}
-        '''.encode('ascii'))  # make python 3 happy
-        opts = {'trimmed': 'true'}
-        assert list(babel_extract(source,
-                                  ('gettext', 'ngettext', '_'), [], opts)) == [
-            (2, 'gettext', u' Hello  \n  World', []),
-            (4, 'gettext', u'Hello World', []),
-            (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None), [])
+        """.encode(
+                "ascii"
+            )
+        )  # make python 3 happy
+        opts = {"trimmed": "true"}
+        assert list(babel_extract(source, ("gettext", "ngettext", "_"), [], opts)) == [
+            (2, "gettext", u" Hello  \n  World", []),
+            (4, "gettext", u"Hello World", []),
+            (6, "ngettext", (u"%(users)s user", u"%(users)s users", None), []),
         ]
 
     def test_comment_extract(self):
         from jinja2.ext import babel_extract
-        source = BytesIO('''
+
+        source = BytesIO(
+            """
         {# trans first #}
         {{ gettext('Hello World') }}
         {% trans %}Hello World{% endtrans %}{# trans second #}
         {#: third #}
         {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
-        '''.encode('utf-8'))  # make python 3 happy
-        assert list(babel_extract(source,
-                                  ('gettext', 'ngettext', '_'),
-                                  ['trans', ':'], {})) == [
-            (3, 'gettext', u'Hello World', ['first']),
-            (4, 'gettext', u'Hello World', ['second']),
-            (6, 'ngettext', (u'%(users)s user', u'%(users)s users', None),
-             ['third'])
+        """.encode(
+                "utf-8"
+            )
+        )  # make python 3 happy
+        assert list(
+            babel_extract(source, ("gettext", "ngettext", "_"), ["trans", ":"], {})
+        ) == [
+            (3, "gettext", u"Hello World", ["first"]),
+            (4, "gettext", u"Hello World", ["second"]),
+            (6, "ngettext", (u"%(users)s user", u"%(users)s users", None), ["third"]),
         ]
 
 
 @pytest.mark.ext
 class TestScope(object):
-
     def test_basic_scope_behavior(self):
         # This is what the old with statement compiled down to
         class ScopeExt(Extension):
-            tags = set(['scope'])
+            tags = set(["scope"])
 
             def parse(self, parser):
                 node = nodes.Scope(lineno=next(parser.stream).lineno)
                 assignments = []
-                while parser.stream.current.type != 'block_end':
+                while parser.stream.current.type != "block_end":
                     lineno = parser.stream.current.lineno
                     if assignments:
-                        parser.stream.expect('comma')
+                        parser.stream.expect("comma")
                     target = parser.parse_assign_target()
-                    parser.stream.expect('assign')
+                    parser.stream.expect("assign")
                     expr = parser.parse_expression()
                     assignments.append(nodes.Assign(target, expr, lineno=lineno))
-                node.body = assignments + \
-                    list(parser.parse_statements(('name:endscope',),
-                                                 drop_needle=True))
+                node.body = assignments + list(
+                    parser.parse_statements(("name:endscope",), drop_needle=True)
+                )
                 return node
 
         env = Environment(extensions=[ScopeExt])
-        tmpl = env.from_string('''\
+        tmpl = env.from_string(
+            """\
         {%- scope a=1, b=2, c=b, d=e, e=5 -%}
             {{ a }}|{{ b }}|{{ c }}|{{ d }}|{{ e }}
         {%- endscope -%}
-        ''')
-        assert tmpl.render(b=3, e=4) == '1|2|2|4|5'
+        """
+        )
+        assert tmpl.render(b=3, e=4) == "1|2|2|4|5"
 
 
 @pytest.mark.ext
 class TestNewstyleInternationalization(object):
-
     def test_trans(self):
-        tmpl = newstyle_i18n_env.get_template('child.html')
-        assert tmpl.render(LANGUAGE='de') == '<title>fehlend</title>pass auf'
+        tmpl = newstyle_i18n_env.get_template("child.html")
+        assert tmpl.render(LANGUAGE="de") == "<title>fehlend</title>pass auf"
 
     def test_trans_plural(self):
-        tmpl = newstyle_i18n_env.get_template('plural.html')
-        assert tmpl.render(LANGUAGE='de', user_count=1) \
-            == 'Ein Benutzer online'
-        assert tmpl.render(LANGUAGE='de', user_count=2) == '2 Benutzer online'
+        tmpl = newstyle_i18n_env.get_template("plural.html")
+        assert tmpl.render(LANGUAGE="de", user_count=1) == "Ein Benutzer online"
+        assert tmpl.render(LANGUAGE="de", user_count=2) == "2 Benutzer online"
 
     def test_complex_plural(self):
         tmpl = newstyle_i18n_env.from_string(
-            '{% trans foo=42, count=2 %}{{ count }} item{% '
-            'pluralize count %}{{ count }} items{% endtrans %}')
-        assert tmpl.render() == '2 items'
-        pytest.raises(TemplateAssertionError, i18n_env.from_string,
-                      '{% trans foo %}...{% pluralize bar %}...{% endtrans %}')
+            "{% trans foo=42, count=2 %}{{ count }} item{% "
+            "pluralize count %}{{ count }} items{% endtrans %}"
+        )
+        assert tmpl.render() == "2 items"
+        pytest.raises(
+            TemplateAssertionError,
+            i18n_env.from_string,
+            "{% trans foo %}...{% pluralize bar %}...{% endtrans %}",
+        )
 
     def test_trans_stringformatting(self):
-        tmpl = newstyle_i18n_env.get_template('stringformat.html')
-        assert tmpl.render(LANGUAGE='de', user_count=5) == 'Benutzer: 5'
+        tmpl = newstyle_i18n_env.get_template("stringformat.html")
+        assert tmpl.render(LANGUAGE="de", user_count=5) == "Benutzer: 5"
 
     def test_newstyle_plural(self):
-        tmpl = newstyle_i18n_env.get_template('ngettext.html')
-        assert tmpl.render(LANGUAGE='de', apples=1) == '1 Apfel'
-        assert tmpl.render(LANGUAGE='de', apples=5) == u'5 Äpfel'
+        tmpl = newstyle_i18n_env.get_template("ngettext.html")
+        assert tmpl.render(LANGUAGE="de", apples=1) == "1 Apfel"
+        assert tmpl.render(LANGUAGE="de", apples=5) == u"5 Äpfel"
 
     def test_autoescape_support(self):
-        env = Environment(extensions=['jinja2.ext.autoescape',
-                                      'jinja2.ext.i18n'])
+        env = Environment(extensions=["jinja2.ext.autoescape", "jinja2.ext.i18n"])
         env.install_gettext_callables(
-            lambda x: u'<strong>Wert: %(name)s</strong>',
-            lambda s, p, n: s, newstyle=True)
-        t = env.from_string('{% autoescape ae %}{{ gettext("foo", name='
-                            '"<test>") }}{% endautoescape %}')
-        assert t.render(ae=True) == '<strong>Wert: &lt;test&gt;</strong>'
-        assert t.render(ae=False) == '<strong>Wert: <test></strong>'
+            lambda x: u"<strong>Wert: %(name)s</strong>",
+            lambda s, p, n: s,
+            newstyle=True,
+        )
+        t = env.from_string(
+            '{% autoescape ae %}{{ gettext("foo", name='
+            '"<test>") }}{% endautoescape %}'
+        )
+        assert t.render(ae=True) == "<strong>Wert: &lt;test&gt;</strong>"
+        assert t.render(ae=False) == "<strong>Wert: <test></strong>"
 
     def test_autoescape_macros(self):
-        env = Environment(autoescape=False, extensions=['jinja2.ext.autoescape'])
+        env = Environment(autoescape=False, extensions=["jinja2.ext.autoescape"])
         template = (
-            '{% macro m() %}<html>{% endmacro %}'
-            '{% autoescape true %}{{ m() }}{% endautoescape %}'
+            "{% macro m() %}<html>{% endmacro %}"
+            "{% autoescape true %}{{ m() }}{% endautoescape %}"
         )
-        assert env.from_string(template).render() == '<html>'
+        assert env.from_string(template).render() == "<html>"
 
     def test_num_used_twice(self):
-        tmpl = newstyle_i18n_env.get_template('ngettext_long.html')
-        assert tmpl.render(apples=5, LANGUAGE='de') == u'5 Äpfel'
+        tmpl = newstyle_i18n_env.get_template("ngettext_long.html")
+        assert tmpl.render(apples=5, LANGUAGE="de") == u"5 Äpfel"
 
     def test_num_called_num(self):
-        source = newstyle_i18n_env.compile('''
+        source = newstyle_i18n_env.compile(
+            """
             {% trans num=3 %}{{ num }} apple{% pluralize
             %}{{ num }} apples{% endtrans %}
-        ''', raw=True)
+        """,
+            raw=True,
+        )
         # quite hacky, but the only way to properly test that.  The idea is
         # that the generated code does not pass num twice (although that
         # would work) for better performance.  This only works on the
         # newstyle gettext of course
-        assert re.search(r"u?'\%\(num\)s apple', u?'\%\(num\)s "
-                         r"apples', 3", source) is not None
+        assert (
+            re.search(r"u?'\%\(num\)s apple', u?'\%\(num\)s " r"apples', 3", source)
+            is not None
+        )
 
     def test_trans_vars(self):
-        t1 = newstyle_i18n_env.get_template('transvars1.html')
-        t2 = newstyle_i18n_env.get_template('transvars2.html')
-        t3 = newstyle_i18n_env.get_template('transvars3.html')
-        assert t1.render(num=1, LANGUAGE='de') == 'Benutzer: 1'
-        assert t2.render(count=23, LANGUAGE='de') == 'Benutzer: 23'
-        assert t3.render(num=42, LANGUAGE='de') == 'Benutzer: 42'
+        t1 = newstyle_i18n_env.get_template("transvars1.html")
+        t2 = newstyle_i18n_env.get_template("transvars2.html")
+        t3 = newstyle_i18n_env.get_template("transvars3.html")
+        assert t1.render(num=1, LANGUAGE="de") == "Benutzer: 1"
+        assert t2.render(count=23, LANGUAGE="de") == "Benutzer: 23"
+        assert t3.render(num=42, LANGUAGE="de") == "Benutzer: 42"
 
     def test_novars_vars_escaping(self):
-        t = newstyle_i18n_env.get_template('novars.html')
-        assert t.render() == '%(hello)s'
-        t = newstyle_i18n_env.get_template('vars.html')
-        assert t.render(foo='42') == '42%(foo)s'
-        t = newstyle_i18n_env.get_template('explicitvars.html')
-        assert t.render() == '%(foo)s'
+        t = newstyle_i18n_env.get_template("novars.html")
+        assert t.render() == "%(hello)s"
+        t = newstyle_i18n_env.get_template("vars.html")
+        assert t.render(foo="42") == "42%(foo)s"
+        t = newstyle_i18n_env.get_template("explicitvars.html")
+        assert t.render() == "%(foo)s"
 
 
 @pytest.mark.ext
 class TestAutoEscape(object):
-
     def test_scoped_setting(self):
-        env = Environment(extensions=['jinja2.ext.autoescape'],
-                          autoescape=True)
-        tmpl = env.from_string('''
+        env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
+        tmpl = env.from_string(
+            """
             {{ "<HelloWorld>" }}
             {% autoescape false %}
                 {{ "<HelloWorld>" }}
             {% endautoescape %}
             {{ "<HelloWorld>" }}
-        ''')
-        assert tmpl.render().split() == \
-            [u'&lt;HelloWorld&gt;', u'<HelloWorld>', u'&lt;HelloWorld&gt;']
+        """
+        )
+        assert tmpl.render().split() == [
+            u"&lt;HelloWorld&gt;",
+            u"<HelloWorld>",
+            u"&lt;HelloWorld&gt;",
+        ]
 
-        env = Environment(extensions=['jinja2.ext.autoescape'],
-                          autoescape=False)
-        tmpl = env.from_string('''
+        env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=False)
+        tmpl = env.from_string(
+            """
             {{ "<HelloWorld>" }}
             {% autoescape true %}
                 {{ "<HelloWorld>" }}
             {% endautoescape %}
             {{ "<HelloWorld>" }}
-        ''')
-        assert tmpl.render().split() == \
-            [u'<HelloWorld>', u'&lt;HelloWorld&gt;', u'<HelloWorld>']
+        """
+        )
+        assert tmpl.render().split() == [
+            u"<HelloWorld>",
+            u"&lt;HelloWorld&gt;",
+            u"<HelloWorld>",
+        ]
 
     def test_nonvolatile(self):
-        env = Environment(extensions=['jinja2.ext.autoescape'],
-                          autoescape=True)
+        env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
         tmpl = env.from_string('{{ {"foo": "<test>"}|xmlattr|escape }}')
         assert tmpl.render() == ' foo="&lt;test&gt;"'
-        tmpl = env.from_string('{% autoescape false %}{{ {"foo": "<test>"}'
-                               '|xmlattr|escape }}{% endautoescape %}')
-        assert tmpl.render() == ' foo=&#34;&amp;lt;test&amp;gt;&#34;'
+        tmpl = env.from_string(
+            '{% autoescape false %}{{ {"foo": "<test>"}'
+            "|xmlattr|escape }}{% endautoescape %}"
+        )
+        assert tmpl.render() == " foo=&#34;&amp;lt;test&amp;gt;&#34;"
 
     def test_volatile(self):
-        env = Environment(extensions=['jinja2.ext.autoescape'],
-                          autoescape=True)
-        tmpl = env.from_string('{% autoescape foo %}{{ {"foo": "<test>"}'
-                               '|xmlattr|escape }}{% endautoescape %}')
-        assert tmpl.render(foo=False) == ' foo=&#34;&amp;lt;test&amp;gt;&#34;'
+        env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
+        tmpl = env.from_string(
+            '{% autoescape foo %}{{ {"foo": "<test>"}'
+            "|xmlattr|escape }}{% endautoescape %}"
+        )
+        assert tmpl.render(foo=False) == " foo=&#34;&amp;lt;test&amp;gt;&#34;"
         assert tmpl.render(foo=True) == ' foo="&lt;test&gt;"'
 
     def test_scoping(self):
-        env = Environment(extensions=['jinja2.ext.autoescape'])
+        env = Environment(extensions=["jinja2.ext.autoescape"])
         tmpl = env.from_string(
             '{% autoescape true %}{% set x = "<x>" %}{{ x }}'
-            '{% endautoescape %}{{ x }}{{ "<y>" }}')
-        assert tmpl.render(x=1) == '&lt;x&gt;1<y>'
+            '{% endautoescape %}{{ x }}{{ "<y>" }}'
+        )
+        assert tmpl.render(x=1) == "&lt;x&gt;1<y>"
 
     def test_volatile_scoping(self):
-        env = Environment(extensions=['jinja2.ext.autoescape'])
-        tmplsource = '''
+        env = Environment(extensions=["jinja2.ext.autoescape"])
+        tmplsource = """
         {% autoescape val %}
             {% macro foo(x) %}
                 [{{ x }}]
@@ -580,41 +625,45 @@ class TestAutoEscape(object):
             {{ foo().__class__.__name__ }}
         {% endautoescape %}
         {{ '<testing>' }}
-        '''
+        """
         tmpl = env.from_string(tmplsource)
-        assert tmpl.render(val=True).split()[0] == 'Markup'
+        assert tmpl.render(val=True).split()[0] == "Markup"
         assert tmpl.render(val=False).split()[0] == text_type.__name__
 
         # looking at the source we should see <testing> there in raw
         # (and then escaped as well)
-        env = Environment(extensions=['jinja2.ext.autoescape'])
+        env = Environment(extensions=["jinja2.ext.autoescape"])
         pysource = env.compile(tmplsource, raw=True)
-        assert '<testing>\\n' in pysource
+        assert "<testing>\\n" in pysource
 
-        env = Environment(extensions=['jinja2.ext.autoescape'],
-                          autoescape=True)
+        env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True)
         pysource = env.compile(tmplsource, raw=True)
-        assert '&lt;testing&gt;\\n' in pysource
+        assert "&lt;testing&gt;\\n" in pysource
 
     def test_overlay_scopes(self):
         class MagicScopeExtension(Extension):
-            tags = set(['overlay'])
+            tags = set(["overlay"])
+
             def parse(self, parser):
                 node = nodes.OverlayScope(lineno=next(parser.stream).lineno)
-                node.body = list(parser.parse_statements(('name:endoverlay',),
-                                                         drop_needle=True))
-                node.context = self.call_method('get_scope')
+                node.body = list(
+                    parser.parse_statements(("name:endoverlay",), drop_needle=True)
+                )
+                node.context = self.call_method("get_scope")
                 return node
+
             def get_scope(self):
-                return {'x': [1, 2, 3]}
+                return {"x": [1, 2, 3]}
 
         env = Environment(extensions=[MagicScopeExtension])
 
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
             {{- x }}|{% set z = 99 %}
             {%- overlay %}
                 {{- y }}|{{ z }}|{% for item in x %}[{{ item }}]{% endfor %}
             {%- endoverlay %}|
             {{- x -}}
-        ''')
-        assert tmpl.render(x=42, y=23) == '42|23|99|[1][2][3]|42'
+        """
+        )
+        assert tmpl.render(x=42, y=23) == "42|23|99|[1][2][3]|42"
index d9ee4e594d1b476380fc98f4b7eb461bac973f88..0d7baedf8eaa05a5b03759c9275528e70cb4de30 100644 (file)
@@ -7,37 +7,35 @@ from jinja2 import Environment
 from jinja2 import Template
 
 
-@pytest.mark.skipif(sys.version_info < (3, 5),
-                    reason='Requires 3.5 or later')
+@pytest.mark.skipif(sys.version_info < (3, 5), reason="Requires 3.5 or later")
 def test_generator_stop():
     class X(object):
         def __getattr__(self, name):
             raise StopIteration()
 
-    t = Template('a{{ bad.bar() }}b')
+    t = Template("a{{ bad.bar() }}b")
     with pytest.raises(RuntimeError):
         t.render(bad=X())
 
 
-@pytest.mark.skipif(sys.version_info[0] > 2,
-                    reason='Feature only supported on 2.x')
+@pytest.mark.skipif(sys.version_info[0] > 2, reason="Feature only supported on 2.x")
 def test_ascii_str():
     @contextfilter
     def assert_func(context, value):
-        assert type(value) is context['expected_type']
+        assert type(value) is context["expected_type"]
 
     env = Environment()
-    env.filters['assert'] = assert_func
+    env.filters["assert"] = assert_func
 
-    env.policies['compiler.ascii_str'] = False
+    env.policies["compiler.ascii_str"] = False
     t = env.from_string('{{ "foo"|assert }}')
     t.render(expected_type=unicode)
 
-    env.policies['compiler.ascii_str'] = True
+    env.policies["compiler.ascii_str"] = True
     t = env.from_string('{{ "foo"|assert }}')
     t.render(expected_type=str)
 
     for val in True, False:
-        env.policies['compiler.ascii_str'] = val
+        env.policies["compiler.ascii_str"] = val
         t = env.from_string(u'{{ "\N{SNOWMAN}"|assert }}')
         t.render(expected_type=unicode)
index b56e35bb81f1d61f2e86650fd8626719488db159..3f74c27571e7effaf6f4e263f943f9cd5ff96b76 100644 (file)
@@ -34,60 +34,66 @@ class Magic2(object):
         self.value2 = value2
 
     def __str__(self):
-        return u'(%s,%s)' % (text_type(self.value1), text_type(self.value2))
+        return u"(%s,%s)" % (text_type(self.value1), text_type(self.value2))
 
 
 @pytest.mark.filter
 class TestFilter(object):
-
     def test_filter_calling(self, env):
-        rv = env.call_filter('sum', [1, 2, 3])
+        rv = env.call_filter("sum", [1, 2, 3])
         assert rv == 6
 
     def test_capitalize(self, env):
         tmpl = env.from_string('{{ "foo bar"|capitalize }}')
-        assert tmpl.render() == 'Foo bar'
+        assert tmpl.render() == "Foo bar"
 
     def test_center(self, env):
         tmpl = env.from_string('{{ "foo"|center(9) }}')
-        assert tmpl.render() == '   foo   '
+        assert tmpl.render() == "   foo   "
 
     def test_default(self, env):
         tmpl = env.from_string(
             "{{ missing|default('no') }}|{{ false|default('no') }}|"
             "{{ false|default('no', true) }}|{{ given|default('no') }}"
         )
-        assert tmpl.render(given='yes') == 'no|False|no|yes'
+        assert tmpl.render(given="yes") == "no|False|no|yes"
 
-    @pytest.mark.parametrize('args,expect', (
-        ('', "[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]"),
-        ('true',  "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]"),
-        ('by="value"',  "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]"),
-        ('reverse=true', "[('c', 2), ('b', 1), ('AB', 3), ('aa', 0)]")
-    ))
+    @pytest.mark.parametrize(
+        "args,expect",
+        (
+            ("", "[('aa', 0), ('AB', 3), ('b', 1), ('c', 2)]"),
+            ("true", "[('AB', 3), ('aa', 0), ('b', 1), ('c', 2)]"),
+            ('by="value"', "[('aa', 0), ('b', 1), ('c', 2), ('AB', 3)]"),
+            ("reverse=true", "[('c', 2), ('b', 1), ('AB', 3), ('aa', 0)]"),
+        ),
+    )
     def test_dictsort(self, env, args, expect):
-        t = env.from_string('{{{{ foo|dictsort({args}) }}}}'.format(args=args))
+        t = env.from_string("{{{{ foo|dictsort({args}) }}}}".format(args=args))
         out = t.render(foo={"aa": 0, "b": 1, "c": 2, "AB": 3})
         assert out == expect
 
     def test_batch(self, env):
-        tmpl = env.from_string("{{ foo|batch(3)|list }}|"
-                               "{{ foo|batch(3, 'X')|list }}")
+        tmpl = env.from_string("{{ foo|batch(3)|list }}|{{ foo|batch(3, 'X')|list }}")
         out = tmpl.render(foo=list(range(10)))
-        assert out == ("[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
-                       "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]")
+        assert out == (
+            "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]|"
+            "[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 'X', 'X']]"
+        )
 
     def test_slice(self, env):
-        tmpl = env.from_string('{{ foo|slice(3)|list }}|'
-                               '{{ foo|slice(3, "X")|list }}')
+        tmpl = env.from_string(
+            "{{ foo|slice(3)|list }}|" '{{ foo|slice(3, "X")|list }}'
+        )
         out = tmpl.render(foo=list(range(10)))
-        assert out == ("[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
-                       "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]")
+        assert out == (
+            "[[0, 1, 2, 3], [4, 5, 6], [7, 8, 9]]|"
+            "[[0, 1, 2, 3], [4, 5, 6, 'X'], [7, 8, 9, 'X']]"
+        )
 
     def test_escape(self, env):
-        tmpl = env.from_string('''{{ '<">&'|escape }}''')
+        tmpl = env.from_string("""{{ '<">&'|escape }}""")
         out = tmpl.render()
-        assert out == '&lt;&#34;&gt;&amp;'
+        assert out == "&lt;&#34;&gt;&amp;"
 
     @pytest.mark.parametrize(
         ("chars", "expect"), [(None, "..stays.."), (".", "  ..stays"), (" .", "stays")]
@@ -98,52 +104,53 @@ class TestFilter(object):
         assert out == expect
 
     def test_striptags(self, env):
-        tmpl = env.from_string('''{{ foo|striptags }}''')
-        out = tmpl.render(foo='  <p>just a small   \n <a href="#">'
-                          'example</a> link</p>\n<p>to a webpage</p> '
-                          '<!-- <p>and some commented stuff</p> -->')
-        assert out == 'just a small example link to a webpage'
+        tmpl = env.from_string("""{{ foo|striptags }}""")
+        out = tmpl.render(
+            foo='  <p>just a small   \n <a href="#">'
+            "example</a> link</p>\n<p>to a webpage</p> "
+            "<!-- <p>and some commented stuff</p> -->"
+        )
+        assert out == "just a small example link to a webpage"
 
     def test_filesizeformat(self, env):
         tmpl = env.from_string(
-            '{{ 100|filesizeformat }}|'
-            '{{ 1000|filesizeformat }}|'
-            '{{ 1000000|filesizeformat }}|'
-            '{{ 1000000000|filesizeformat }}|'
-            '{{ 1000000000000|filesizeformat }}|'
-            '{{ 100|filesizeformat(true) }}|'
-            '{{ 1000|filesizeformat(true) }}|'
-            '{{ 1000000|filesizeformat(true) }}|'
-            '{{ 1000000000|filesizeformat(true) }}|'
-            '{{ 1000000000000|filesizeformat(true) }}'
+            "{{ 100|filesizeformat }}|"
+            "{{ 1000|filesizeformat }}|"
+            "{{ 1000000|filesizeformat }}|"
+            "{{ 1000000000|filesizeformat }}|"
+            "{{ 1000000000000|filesizeformat }}|"
+            "{{ 100|filesizeformat(true) }}|"
+            "{{ 1000|filesizeformat(true) }}|"
+            "{{ 1000000|filesizeformat(true) }}|"
+            "{{ 1000000000|filesizeformat(true) }}|"
+            "{{ 1000000000000|filesizeformat(true) }}"
         )
         out = tmpl.render()
         assert out == (
-            '100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|'
-            '1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB'
+            "100 Bytes|1.0 kB|1.0 MB|1.0 GB|1.0 TB|100 Bytes|"
+            "1000 Bytes|976.6 KiB|953.7 MiB|931.3 GiB"
         )
 
     def test_filesizeformat_issue59(self, env):
         tmpl = env.from_string(
-            '{{ 300|filesizeformat }}|'
-            '{{ 3000|filesizeformat }}|'
-            '{{ 3000000|filesizeformat }}|'
-            '{{ 3000000000|filesizeformat }}|'
-            '{{ 3000000000000|filesizeformat }}|'
-            '{{ 300|filesizeformat(true) }}|'
-            '{{ 3000|filesizeformat(true) }}|'
-            '{{ 3000000|filesizeformat(true) }}'
+            "{{ 300|filesizeformat }}|"
+            "{{ 3000|filesizeformat }}|"
+            "{{ 3000000|filesizeformat }}|"
+            "{{ 3000000000|filesizeformat }}|"
+            "{{ 3000000000000|filesizeformat }}|"
+            "{{ 300|filesizeformat(true) }}|"
+            "{{ 3000|filesizeformat(true) }}|"
+            "{{ 3000000|filesizeformat(true) }}"
         )
         out = tmpl.render()
         assert out == (
-            '300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|'
-            '2.9 KiB|2.9 MiB'
+            "300 Bytes|3.0 kB|3.0 MB|3.0 GB|3.0 TB|300 Bytes|2.9 KiB|2.9 MiB"
         )
 
     def test_first(self, env):
-        tmpl = env.from_string('{{ foo|first }}')
+        tmpl = env.from_string("{{ foo|first }}")
         out = tmpl.render(foo=list(range(10)))
-        assert out == '0'
+        assert out == "0"
 
     @pytest.mark.parametrize(
         ("value", "expect"), (("42", "42.0"), ("abc", "0.0"), ("32.32", "32.32"),)
@@ -157,37 +164,37 @@ class TestFilter(object):
         assert t.render(value="abc") == "1.0"
 
     def test_format(self, env):
-        tmpl = env.from_string('''{{ "%s|%s"|format("a", "b") }}''')
+        tmpl = env.from_string("""{{ "%s|%s"|format("a", "b") }}""")
         out = tmpl.render()
-        assert out == 'a|b'
+        assert out == "a|b"
 
     @staticmethod
     def _test_indent_multiline_template(env, markup=False):
-        text = '\n'.join(['', 'foo bar', '"baz"', ''])
+        text = "\n".join(["", "foo bar", '"baz"', ""])
         if markup:
             text = Markup(text)
-        t = env.from_string('{{ foo|indent(2, false, false) }}')
+        t = env.from_string("{{ foo|indent(2, false, false) }}")
         assert t.render(foo=text) == '\n  foo bar\n  "baz"\n'
-        t = env.from_string('{{ foo|indent(2, false, true) }}')
+        t = env.from_string("{{ foo|indent(2, false, true) }}")
         assert t.render(foo=text) == '\n  foo bar\n  "baz"\n  '
-        t = env.from_string('{{ foo|indent(2, true, false) }}')
+        t = env.from_string("{{ foo|indent(2, true, false) }}")
         assert t.render(foo=text) == '  \n  foo bar\n  "baz"\n'
-        t = env.from_string('{{ foo|indent(2, true, true) }}')
+        t = env.from_string("{{ foo|indent(2, true, true) }}")
         assert t.render(foo=text) == '  \n  foo bar\n  "baz"\n  '
 
     def test_indent(self, env):
         self._test_indent_multiline_template(env)
         t = env.from_string('{{ "jinja"|indent }}')
-        assert t.render() == 'jinja'
+        assert t.render() == "jinja"
         t = env.from_string('{{ "jinja"|indent(first=true) }}')
-        assert t.render() == '    jinja'
+        assert t.render() == "    jinja"
         t = env.from_string('{{ "jinja"|indent(blank=true) }}')
-        assert t.render() == 'jinja'
+        assert t.render() == "jinja"
 
     def test_indent_markup_input(self, env):
-        '''
+        """
         Tests cases where the filter input is a Markup type
-        '''
+        """
         self._test_indent_multiline_template(env, markup=True)
 
     def test_indentfirst_deprecated(self, env):
@@ -201,7 +208,7 @@ class TestFilter(object):
             ("abc", "0"),
             ("32.32", "32"),
             ("12345678901234567890", "12345678901234567890"),
-        )
+        ),
     )
     def test_int(self, env, value, expect):
         t = env.from_string("{{ '%s'|int }}" % value)
@@ -209,11 +216,7 @@ class TestFilter(object):
 
     @pytest.mark.parametrize(
         ("value", "base", "expect"),
-        (
-            ("0x4d32", 16, "19762"),
-            ("011", 8, "9"),
-            ("0x33Z", 16, "0"),
-        )
+        (("0x4d32", 16, "19762"), ("011", 8, "9"), ("0x33Z", 16, "0"),),
     )
     def test_int_base(self, env, value, base, expect):
         t = env.from_string("{{ '%s'|int(base=%d) }}" % (value, base))
@@ -234,38 +237,39 @@ class TestFilter(object):
     def test_join(self, env):
         tmpl = env.from_string('{{ [1, 2, 3]|join("|") }}')
         out = tmpl.render()
-        assert out == '1|2|3'
+        assert out == "1|2|3"
 
         env2 = Environment(autoescape=True)
-        tmpl = env2.from_string(
-            '{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
-        assert tmpl.render() == '&lt;foo&gt;<span>foo</span>'
+        tmpl = env2.from_string('{{ ["<foo>", "<span>foo</span>"|safe]|join }}')
+        assert tmpl.render() == "&lt;foo&gt;<span>foo</span>"
 
     def test_join_attribute(self, env):
         class User(object):
             def __init__(self, username):
                 self.username = username
-        tmpl = env.from_string('''{{ users|join(', ', 'username') }}''')
-        assert tmpl.render(users=map(User, ['foo', 'bar'])) == 'foo, bar'
+
+        tmpl = env.from_string("""{{ users|join(', ', 'username') }}""")
+        assert tmpl.render(users=map(User, ["foo", "bar"])) == "foo, bar"
 
     def test_last(self, env):
-        tmpl = env.from_string('''{{ foo|last }}''')
+        tmpl = env.from_string("""{{ foo|last }}""")
         out = tmpl.render(foo=list(range(10)))
-        assert out == '9'
+        assert out == "9"
 
     def test_length(self, env):
-        tmpl = env.from_string('''{{ "hello world"|length }}''')
+        tmpl = env.from_string("""{{ "hello world"|length }}""")
         out = tmpl.render()
-        assert out == '11'
+        assert out == "11"
 
     def test_lower(self, env):
-        tmpl = env.from_string('''{{ "FOO"|lower }}''')
+        tmpl = env.from_string("""{{ "FOO"|lower }}""")
         out = tmpl.render()
-        assert out == 'foo'
+        assert out == "foo"
 
     def test_pprint(self, env):
         from pprint import pformat
-        tmpl = env.from_string('''{{ data|pprint }}''')
+
+        tmpl = env.from_string("""{{ data|pprint }}""")
         data = list(range(1000))
         assert tmpl.render(data=data) == pformat(data)
 
@@ -274,177 +278,173 @@ class TestFilter(object):
         state = random.getstate()
         request.addfinalizer(lambda: random.setstate(state))
         # generate the random values from a known seed
-        random.seed('jinja')
-        expected = [random.choice('1234567890') for _ in range(10)]
+        random.seed("jinja")
+        expected = [random.choice("1234567890") for _ in range(10)]
 
         # check that the random sequence is generated again by a template
         # ensures that filter result is not constant folded
-        random.seed('jinja')
+        random.seed("jinja")
         t = env.from_string('{{ "1234567890"|random }}')
 
         for value in expected:
             assert t.render() == value
 
     def test_reverse(self, env):
-        tmpl = env.from_string('{{ "foobar"|reverse|join }}|'
-                               '{{ [1, 2, 3]|reverse|list }}')
-        assert tmpl.render() == 'raboof|[3, 2, 1]'
+        tmpl = env.from_string(
+            '{{ "foobar"|reverse|join }}|' "{{ [1, 2, 3]|reverse|list }}"
+        )
+        assert tmpl.render() == "raboof|[3, 2, 1]"
 
     def test_string(self, env):
         x = [1, 2, 3, 4, 5]
-        tmpl = env.from_string('''{{ obj|string }}''')
+        tmpl = env.from_string("""{{ obj|string }}""")
         assert tmpl.render(obj=x) == text_type(x)
 
     def test_title(self, env):
-        tmpl = env.from_string('''{{ "foo bar"|title }}''')
+        tmpl = env.from_string("""{{ "foo bar"|title }}""")
         assert tmpl.render() == "Foo Bar"
-        tmpl = env.from_string('''{{ "foo's bar"|title }}''')
+        tmpl = env.from_string("""{{ "foo's bar"|title }}""")
         assert tmpl.render() == "Foo's Bar"
-        tmpl = env.from_string('''{{ "foo   bar"|title }}''')
+        tmpl = env.from_string("""{{ "foo   bar"|title }}""")
         assert tmpl.render() == "Foo   Bar"
-        tmpl = env.from_string('''{{ "f bar f"|title }}''')
+        tmpl = env.from_string("""{{ "f bar f"|title }}""")
         assert tmpl.render() == "F Bar F"
-        tmpl = env.from_string('''{{ "foo-bar"|title }}''')
+        tmpl = env.from_string("""{{ "foo-bar"|title }}""")
         assert tmpl.render() == "Foo-Bar"
-        tmpl = env.from_string('''{{ "foo\tbar"|title }}''')
+        tmpl = env.from_string("""{{ "foo\tbar"|title }}""")
         assert tmpl.render() == "Foo\tBar"
-        tmpl = env.from_string('''{{ "FOO\tBAR"|title }}''')
+        tmpl = env.from_string("""{{ "FOO\tBAR"|title }}""")
         assert tmpl.render() == "Foo\tBar"
-        tmpl = env.from_string('''{{ "foo (bar)"|title }}''')
+        tmpl = env.from_string("""{{ "foo (bar)"|title }}""")
         assert tmpl.render() == "Foo (Bar)"
-        tmpl = env.from_string('''{{ "foo {bar}"|title }}''')
+        tmpl = env.from_string("""{{ "foo {bar}"|title }}""")
         assert tmpl.render() == "Foo {Bar}"
-        tmpl = env.from_string('''{{ "foo [bar]"|title }}''')
+        tmpl = env.from_string("""{{ "foo [bar]"|title }}""")
         assert tmpl.render() == "Foo [Bar]"
-        tmpl = env.from_string('''{{ "foo <bar>"|title }}''')
+        tmpl = env.from_string("""{{ "foo <bar>"|title }}""")
         assert tmpl.render() == "Foo <Bar>"
 
         class Foo:
             def __str__(self):
-                return 'foo-bar'
+                return "foo-bar"
 
-        tmpl = env.from_string('''{{ data|title }}''')
+        tmpl = env.from_string("""{{ data|title }}""")
         out = tmpl.render(data=Foo())
-        assert out == 'Foo-Bar'
+        assert out == "Foo-Bar"
 
     def test_truncate(self, env):
         tmpl = env.from_string(
             '{{ data|truncate(15, true, ">>>") }}|'
             '{{ data|truncate(15, false, ">>>") }}|'
-            '{{ smalldata|truncate(15) }}'
+            "{{ smalldata|truncate(15) }}"
         )
-        out = tmpl.render(data='foobar baz bar' * 1000,
-                          smalldata='foobar baz bar')
-        msg = 'Current output: %s' % out
-        assert out == 'foobar baz b>>>|foobar baz>>>|foobar baz bar', msg
+        out = tmpl.render(data="foobar baz bar" * 1000, smalldata="foobar baz bar")
+        msg = "Current output: %s" % out
+        assert out == "foobar baz b>>>|foobar baz>>>|foobar baz bar", msg
 
     def test_truncate_very_short(self, env):
         tmpl = env.from_string(
-            '{{ "foo bar baz"|truncate(9) }}|'
-            '{{ "foo bar baz"|truncate(9, true) }}'
+            '{{ "foo bar baz"|truncate(9) }}|{{ "foo bar baz"|truncate(9, true) }}'
         )
         out = tmpl.render()
-        assert out == 'foo bar baz|foo bar baz', out
+        assert out == "foo bar baz|foo bar baz", out
 
     def test_truncate_end_length(self, env):
         tmpl = env.from_string('{{ "Joel is a slug"|truncate(7, true) }}')
         out = tmpl.render()
-        assert out == 'Joel...', 'Current output: %s' % out
+        assert out == "Joel...", "Current output: %s" % out
 
     def test_upper(self, env):
         tmpl = env.from_string('{{ "foo"|upper }}')
-        assert tmpl.render() == 'FOO'
+        assert tmpl.render() == "FOO"
 
     def test_urlize(self, env):
-        tmpl = env.from_string(
-            '{{ "foo http://www.example.com/ bar"|urlize }}')
+        tmpl = env.from_string('{{ "foo http://www.example.com/ bar"|urlize }}')
         assert tmpl.render() == (
             'foo <a href="http://www.example.com/" rel="noopener">'
-            'http://www.example.com/</a> bar'
+            "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 }}')
+        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'
+            '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/" rel="noopener" target="_blank">'\
-            'http://www.example.com/</a> bar'
+        assert (
+            tmpl.render()
+            == 'foo <a href="http://www.example.com/" rel="noopener" target="_blank">'
+            "http://www.example.com/</a> bar"
+        )
 
     def test_wordcount(self, env):
         tmpl = env.from_string('{{ "foo bar baz"|wordcount }}')
-        assert tmpl.render() == '3'
+        assert tmpl.render() == "3"
 
     def test_block(self, env):
-        tmpl = env.from_string(
-            '{% filter lower|escape %}<HEHE>{% endfilter %}'
-        )
-        assert tmpl.render() == '&lt;hehe&gt;'
+        tmpl = env.from_string("{% filter lower|escape %}<HEHE>{% endfilter %}")
+        assert tmpl.render() == "&lt;hehe&gt;"
 
     def test_chaining(self, env):
-        tmpl = env.from_string(
-            '''{{ ['<foo>', '<bar>']|first|upper|escape }}'''
-        )
-        assert tmpl.render() == '&lt;FOO&gt;'
+        tmpl = env.from_string("""{{ ['<foo>', '<bar>']|first|upper|escape }}""")
+        assert tmpl.render() == "&lt;FOO&gt;"
 
     def test_sum(self, env):
-        tmpl = env.from_string('''{{ [1, 2, 3, 4, 5, 6]|sum }}''')
-        assert tmpl.render() == '21'
+        tmpl = env.from_string("""{{ [1, 2, 3, 4, 5, 6]|sum }}""")
+        assert tmpl.render() == "21"
 
     def test_sum_attributes(self, env):
-        tmpl = env.from_string('''{{ values|sum('value') }}''')
-        assert tmpl.render(values=[
-            {'value': 23},
-            {'value': 1},
-            {'value': 18},
-        ]) == '42'
+        tmpl = env.from_string("""{{ values|sum('value') }}""")
+        assert tmpl.render(values=[{"value": 23}, {"value": 1}, {"value": 18},]) == "42"
 
     def test_sum_attributes_nested(self, env):
-        tmpl = env.from_string('''{{ values|sum('real.value') }}''')
-        assert tmpl.render(values=[
-            {'real': {'value': 23}},
-            {'real': {'value': 1}},
-            {'real': {'value': 18}},
-        ]) == '42'
+        tmpl = env.from_string("""{{ values|sum('real.value') }}""")
+        assert (
+            tmpl.render(
+                values=[
+                    {"real": {"value": 23}},
+                    {"real": {"value": 1}},
+                    {"real": {"value": 18}},
+                ]
+            )
+            == "42"
+        )
 
     def test_sum_attributes_tuple(self, env):
-        tmpl = env.from_string('''{{ values.items()|sum('1') }}''')
-        assert tmpl.render(values={
-            'foo': 23,
-            'bar': 1,
-            'baz': 18,
-        }) == '42'
+        tmpl = env.from_string("""{{ values.items()|sum('1') }}""")
+        assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18,}) == "42"
 
     def test_abs(self, env):
-        tmpl = env.from_string('''{{ -1|abs }}|{{ 1|abs }}''')
-        assert tmpl.render() == '1|1', tmpl.render()
+        tmpl = env.from_string("""{{ -1|abs }}|{{ 1|abs }}""")
+        assert tmpl.render() == "1|1", tmpl.render()
 
     def test_round_positive(self, env):
-        tmpl = env.from_string('{{ 2.7|round }}|{{ 2.1|round }}|'
-                               "{{ 2.1234|round(3, 'floor') }}|"
-                               "{{ 2.1|round(0, 'ceil') }}")
-        assert tmpl.render() == '3.0|2.0|2.123|3.0', tmpl.render()
+        tmpl = env.from_string(
+            "{{ 2.7|round }}|{{ 2.1|round }}|"
+            "{{ 2.1234|round(3, 'floor') }}|"
+            "{{ 2.1|round(0, 'ceil') }}"
+        )
+        assert tmpl.render() == "3.0|2.0|2.123|3.0", tmpl.render()
 
     def test_round_negative(self, env):
-        tmpl = env.from_string('{{ 21.3|round(-1)}}|'
-                               "{{ 21.3|round(-1, 'ceil')}}|"
-                               "{{ 21.3|round(-1, 'floor')}}")
-        assert tmpl.render() == '20.0|30.0|20.0', tmpl.render()
+        tmpl = env.from_string(
+            "{{ 21.3|round(-1)}}|"
+            "{{ 21.3|round(-1, 'ceil')}}|"
+            "{{ 21.3|round(-1, 'floor')}}"
+        )
+        assert tmpl.render() == "20.0|30.0|20.0", tmpl.render()
 
     def test_xmlattr(self, env):
         tmpl = env.from_string(
             "{{ {'foo': 42, 'bar': 23, 'fish': none, "
-            "'spam': missing, 'blub:blub': '<?>'}|xmlattr }}")
+            "'spam': missing, 'blub:blub': '<?>'}|xmlattr }}"
+        )
         out = tmpl.render().split()
         assert len(out) == 3
         assert 'foo="42"' in out
@@ -452,44 +452,60 @@ class TestFilter(object):
         assert 'blub:blub="&lt;?&gt;"' in out
 
     def test_sort1(self, env):
-        tmpl = env.from_string(
-            '{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}')
-        assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
+        tmpl = env.from_string("{{ [2, 3, 1]|sort }}|{{ [2, 3, 1]|sort(true) }}")
+        assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
 
     def test_sort2(self, env):
         tmpl = env.from_string('{{ "".join(["c", "A", "b", "D"]|sort) }}')
-        assert tmpl.render() == 'AbcD'
+        assert tmpl.render() == "AbcD"
 
     def test_sort3(self, env):
-        tmpl = env.from_string('''{{ ['foo', 'Bar', 'blah']|sort }}''')
+        tmpl = env.from_string("""{{ ['foo', 'Bar', 'blah']|sort }}""")
         assert tmpl.render() == "['Bar', 'blah', 'foo']"
 
     def test_sort4(self, env):
-        tmpl = env.from_string('''{{ items|sort(attribute='value')|join }}''')
-        assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == '1234'
+        tmpl = env.from_string("""{{ items|sort(attribute='value')|join }}""")
+        assert tmpl.render(items=map(Magic, [3, 2, 4, 1])) == "1234"
 
     def test_sort5(self, env):
-        tmpl = env.from_string('''{{ items|sort(attribute='value.0')|join }}''')
-        assert tmpl.render(items=map(Magic, [[3], [2], [4], [1]])) == '[1][2][3][4]'
+        tmpl = env.from_string("""{{ items|sort(attribute='value.0')|join }}""")
+        assert tmpl.render(items=map(Magic, [[3], [2], [4], [1]])) == "[1][2][3][4]"
 
     def test_sort6(self, env):
-        tmpl = env.from_string('''{{ items|sort(attribute='value1,value2')|join }}''')
-        assert (tmpl.render(items=map(
-            lambda x: Magic2(x[0], x[1]), [(3, 1), (2, 2), (2, 1), (2, 5)]))
-            == '(2,1)(2,2)(2,5)(3,1)')
+        tmpl = env.from_string("""{{ items|sort(attribute='value1,value2')|join }}""")
+        assert (
+            tmpl.render(
+                items=map(
+                    lambda x: Magic2(x[0], x[1]), [(3, 1), (2, 2), (2, 1), (2, 5)]
+                )
+            )
+            == "(2,1)(2,2)(2,5)(3,1)"
+        )
 
     def test_sort7(self, env):
-        tmpl = env.from_string('''{{ items|sort(attribute='value2,value1')|join }}''')
-        assert (tmpl.render(items=map(lambda x: Magic2(x[0], x[1]), [(3, 1), (2, 2), (2, 1), (2, 5)])) ==
-                '(2,1)(3,1)(2,2)(2,5)')
+        tmpl = env.from_string("""{{ items|sort(attribute='value2,value1')|join }}""")
+        assert (
+            tmpl.render(
+                items=map(
+                    lambda x: Magic2(x[0], x[1]), [(3, 1), (2, 2), (2, 1), (2, 5)]
+                )
+            )
+            == "(2,1)(3,1)(2,2)(2,5)"
+        )
 
     def test_sort8(self, env):
         tmpl = env.from_string(
-            '''{{ items|sort(attribute='value1.0,value2.0')|join }}''')
-        assert (tmpl.render(items=map(
-            lambda x: Magic2(x[0], x[1]),
-            [([3], [1]), ([2], [2]), ([2], [1]), ([2], [5])]))
-            == '([2],[1])([2],[2])([2],[5])([3],[1])')
+            """{{ items|sort(attribute='value1.0,value2.0')|join }}"""
+        )
+        assert (
+            tmpl.render(
+                items=map(
+                    lambda x: Magic2(x[0], x[1]),
+                    [([3], [1]), ([2], [2]), ([2], [1]), ([2], [5])],
+                )
+            )
+            == "([2],[1])([2],[2])([2],[5])([3],[1])"
+        )
 
     def test_unique(self, env):
         t = env.from_string('{{ "".join(["b", "A", "a", "b"]|unique) }}')
@@ -501,49 +517,48 @@ class TestFilter(object):
 
     def test_unique_attribute(self, env):
         t = env.from_string("{{ items|unique(attribute='value')|join }}")
-        assert t.render(items=map(Magic, [3, 2, 4, 1, 2])) == '3241'
-
-    @pytest.mark.parametrize('source,expect', (
-        ('{{ ["a", "B"]|min }}', 'a'),
-        ('{{ ["a", "B"]|min(case_sensitive=true) }}', 'B'),
-        ('{{ []|min }}', ''),
-        ('{{ ["a", "B"]|max }}', 'B'),
-        ('{{ ["a", "B"]|max(case_sensitive=true) }}', 'a'),
-        ('{{ []|max }}', ''),
-    ))
+        assert t.render(items=map(Magic, [3, 2, 4, 1, 2])) == "3241"
+
+    @pytest.mark.parametrize(
+        "source,expect",
+        (
+            ('{{ ["a", "B"]|min }}', "a"),
+            ('{{ ["a", "B"]|min(case_sensitive=true) }}', "B"),
+            ("{{ []|min }}", ""),
+            ('{{ ["a", "B"]|max }}', "B"),
+            ('{{ ["a", "B"]|max(case_sensitive=true) }}', "a"),
+            ("{{ []|max }}", ""),
+        ),
+    )
     def test_min_max(self, env, source, expect):
         t = env.from_string(source)
         assert t.render() == expect
 
-    @pytest.mark.parametrize('name,expect', (
-        ('min', '1'),
-        ('max', '9'),
-    ))
+    @pytest.mark.parametrize("name,expect", (("min", "1"), ("max", "9"),))
     def test_min_max_attribute(self, env, name, expect):
-        t = env.from_string('{{ items|' + name + '(attribute="value") }}')
+        t = env.from_string("{{ items|" + name + '(attribute="value") }}')
         assert t.render(items=map(Magic, [5, 1, 9])) == expect
 
     def test_groupby(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
         {%- for grouper, list in [{'foo': 1, 'bar': 2},
                                   {'foo': 2, 'bar': 3},
                                   {'foo': 1, 'bar': 1},
                                   {'foo': 3, 'bar': 4}]|groupby('foo') -%}
             {{ grouper }}{% for x in list %}: {{ x.foo }}, {{ x.bar }}{% endfor %}|
-        {%- endfor %}''')
-        assert tmpl.render().split('|') == [
-            "1: 1, 2: 1, 1",
-            "2: 2, 3",
-            "3: 3, 4",
-            ""
-        ]
+        {%- endfor %}"""
+        )
+        assert tmpl.render().split("|") == ["1: 1, 2: 1, 1", "2: 2, 3", "3: 3, 4", ""]
 
     def test_groupby_tuple_index(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
         {%- for grouper, list in [('a', 1), ('a', 2), ('b', 1)]|groupby(0) -%}
             {{ grouper }}{% for x in list %}:{{ x.1 }}{% endfor %}|
-        {%- endfor %}''')
-        assert tmpl.render() == 'a:1:2|b:1|'
+        {%- endfor %}"""
+        )
+        assert tmpl.render() == "a:1:2|b:1|"
 
     def test_groupby_multidot(self, env):
         class Date(object):
@@ -556,49 +571,53 @@ class TestFilter(object):
             def __init__(self, title, *date):
                 self.date = Date(*date)
                 self.title = title
+
         articles = [
-            Article('aha', 1, 1, 1970),
-            Article('interesting', 2, 1, 1970),
-            Article('really?', 3, 1, 1970),
-            Article('totally not', 1, 1, 1971)
+            Article("aha", 1, 1, 1970),
+            Article("interesting", 2, 1, 1970),
+            Article("really?", 3, 1, 1970),
+            Article("totally not", 1, 1, 1971),
         ]
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
         {%- for year, list in articles|groupby('date.year') -%}
             {{ year }}{% for x in list %}[{{ x.title }}]{% endfor %}|
-        {%- endfor %}''')
-        assert tmpl.render(articles=articles).split('|') == [
-            '1970[aha][interesting][really?]',
-            '1971[totally not]',
-            ''
+        {%- endfor %}"""
+        )
+        assert tmpl.render(articles=articles).split("|") == [
+            "1970[aha][interesting][really?]",
+            "1971[totally not]",
+            "",
         ]
 
     def test_filtertag(self, env):
-        tmpl = env.from_string("{% filter upper|replace('FOO', 'foo') %}"
-                               "foobar{% endfilter %}")
-        assert tmpl.render() == 'fooBAR'
+        tmpl = env.from_string(
+            "{% filter upper|replace('FOO', 'foo') %}foobar{% endfilter %}"
+        )
+        assert tmpl.render() == "fooBAR"
 
     def test_replace(self, env):
         env = Environment()
         tmpl = env.from_string('{{ string|replace("o", 42) }}')
-        assert tmpl.render(string='<foo>') == '<f4242>'
+        assert tmpl.render(string="<foo>") == "<f4242>"
         env = Environment(autoescape=True)
         tmpl = env.from_string('{{ string|replace("o", 42) }}')
-        assert tmpl.render(string='<foo>') == '&lt;f4242&gt;'
+        assert tmpl.render(string="<foo>") == "&lt;f4242&gt;"
         tmpl = env.from_string('{{ string|replace("<", 42) }}')
-        assert tmpl.render(string='<foo>') == '42foo&gt;'
+        assert tmpl.render(string="<foo>") == "42foo&gt;"
         tmpl = env.from_string('{{ string|replace("o", ">x<") }}')
-        assert tmpl.render(string=Markup('foo')) == 'f&gt;x&lt;&gt;x&lt;'
+        assert tmpl.render(string=Markup("foo")) == "f&gt;x&lt;&gt;x&lt;"
 
     def test_forceescape(self, env):
-        tmpl = env.from_string('{{ x|forceescape }}')
-        assert tmpl.render(x=Markup('<div />')) == u'&lt;div /&gt;'
+        tmpl = env.from_string("{{ x|forceescape }}")
+        assert tmpl.render(x=Markup("<div />")) == u"&lt;div /&gt;"
 
     def test_safe(self, env):
         env = Environment(autoescape=True)
         tmpl = env.from_string('{{ "<div>foo</div>"|safe }}')
-        assert tmpl.render() == '<div>foo</div>'
+        assert tmpl.render() == "<div>foo</div>"
         tmpl = env.from_string('{{ "<div>foo</div>" }}')
-        assert tmpl.render() == '&lt;div&gt;foo&lt;/div&gt;'
+        assert tmpl.render() == "&lt;div&gt;foo&lt;/div&gt;"
 
     @pytest.mark.parametrize(
         ("value", "expect"),
@@ -606,11 +625,11 @@ class TestFilter(object):
             ("Hello, world!", "Hello%2C%20world%21"),
             (u"Hello, world\u203d", "Hello%2C%20world%E2%80%BD"),
             ({"f": 1}, "f=1"),
-            ([('f', 1), ("z", 2)], "f=1&amp;z=2"),
+            ([("f", 1), ("z", 2)], "f=1&amp;z=2"),
             ({u"\u203d": 1}, "%E2%80%BD=1"),
             ({0: 1}, "0=1"),
             ([("a b/c", "a b/c")], "a+b%2Fc=a+b%2Fc"),
-            ("a b/c", "a%20b/c")
+            ("a b/c", "a%20b/c"),
         ],
     )
     def test_urlencode(self, value, expect):
@@ -621,29 +640,30 @@ class TestFilter(object):
     def test_simple_map(self, env):
         env = Environment()
         tmpl = env.from_string('{{ ["1", "2", "3"]|map("int")|sum }}')
-        assert tmpl.render() == '6'
+        assert tmpl.render() == "6"
 
     def test_map_sum(self, env):
         tmpl = env.from_string('{{ [[1,2], [3], [4,5,6]]|map("sum")|list }}')
-        assert tmpl.render() == '[3, 3, 15]'
+        assert tmpl.render() == "[3, 3, 15]"
 
     def test_attribute_map(self, env):
         class User(object):
             def __init__(self, name):
                 self.name = name
+
         env = Environment()
         users = [
-            User('john'),
-            User('jane'),
-            User('mike'),
+            User("john"),
+            User("jane"),
+            User("mike"),
         ]
         tmpl = env.from_string('{{ users|map(attribute="name")|join("|") }}')
-        assert tmpl.render(users=users) == 'john|jane|mike'
+        assert tmpl.render(users=users) == "john|jane|mike"
 
     def test_empty_map(self, env):
         env = Environment()
         tmpl = env.from_string('{{ none|map("upper")|list }}')
-        assert tmpl.render() == '[]'
+        assert tmpl.render() == "[]"
 
     def test_map_default(self, env):
         class Fullname(object):
@@ -663,109 +683,112 @@ class TestFilter(object):
             Fullname("john", "lennon"),
             Fullname("jane", "edwards"),
             Fullname("jon", None),
-            Firstname("mike")
+            Firstname("mike"),
         ]
         assert tmpl.render(users=users) == "lennon, edwards, None, smith"
 
     def test_simple_select(self, env):
         env = Environment()
         tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|select("odd")|join("|") }}')
-        assert tmpl.render() == '1|3|5'
+        assert tmpl.render() == "1|3|5"
 
     def test_bool_select(self, env):
         env = Environment()
-        tmpl = env.from_string(
-            '{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}'
-        )
-        assert tmpl.render() == '1|2|3|4|5'
+        tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|select|join("|") }}')
+        assert tmpl.render() == "1|2|3|4|5"
 
     def test_simple_reject(self, env):
         env = Environment()
         tmpl = env.from_string('{{ [1, 2, 3, 4, 5]|reject("odd")|join("|") }}')
-        assert tmpl.render() == '2|4'
+        assert tmpl.render() == "2|4"
 
     def test_bool_reject(self, env):
         env = Environment()
-        tmpl = env.from_string(
-            '{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}'
-        )
-        assert tmpl.render() == 'None|False|0'
+        tmpl = env.from_string('{{ [none, false, 0, 1, 2, 3, 4, 5]|reject|join("|") }}')
+        assert tmpl.render() == "None|False|0"
 
     def test_simple_select_attr(self, env):
         class User(object):
             def __init__(self, name, is_active):
                 self.name = name
                 self.is_active = is_active
+
         env = Environment()
         users = [
-            User('john', True),
-            User('jane', True),
-            User('mike', False),
+            User("john", True),
+            User("jane", True),
+            User("mike", False),
         ]
         tmpl = env.from_string(
-            '{{ users|selectattr("is_active")|'
-            'map(attribute="name")|join("|") }}'
+            '{{ users|selectattr("is_active")|map(attribute="name")|join("|") }}'
         )
-        assert tmpl.render(users=users) == 'john|jane'
+        assert tmpl.render(users=users) == "john|jane"
 
     def test_simple_reject_attr(self, env):
         class User(object):
             def __init__(self, name, is_active):
                 self.name = name
                 self.is_active = is_active
+
         env = Environment()
         users = [
-            User('john', True),
-            User('jane', True),
-            User('mike', False),
+            User("john", True),
+            User("jane", True),
+            User("mike", False),
         ]
-        tmpl = env.from_string('{{ users|rejectattr("is_active")|'
-                               'map(attribute="name")|join("|") }}')
-        assert tmpl.render(users=users) == 'mike'
+        tmpl = env.from_string(
+            '{{ users|rejectattr("is_active")|map(attribute="name")|join("|") }}'
+        )
+        assert tmpl.render(users=users) == "mike"
 
     def test_func_select_attr(self, env):
         class User(object):
             def __init__(self, id, name):
                 self.id = id
                 self.name = name
+
         env = Environment()
         users = [
-            User(1, 'john'),
-            User(2, 'jane'),
-            User(3, 'mike'),
+            User(1, "john"),
+            User(2, "jane"),
+            User(3, "mike"),
         ]
-        tmpl = env.from_string('{{ users|selectattr("id", "odd")|'
-                               'map(attribute="name")|join("|") }}')
-        assert tmpl.render(users=users) == 'john|mike'
+        tmpl = env.from_string(
+            '{{ users|selectattr("id", "odd")|map(attribute="name")|join("|") }}'
+        )
+        assert tmpl.render(users=users) == "john|mike"
 
     def test_func_reject_attr(self, env):
         class User(object):
             def __init__(self, id, name):
                 self.id = id
                 self.name = name
+
         env = Environment()
         users = [
-            User(1, 'john'),
-            User(2, 'jane'),
-            User(3, 'mike'),
+            User(1, "john"),
+            User(2, "jane"),
+            User(3, "mike"),
         ]
-        tmpl = env.from_string('{{ users|rejectattr("id", "odd")|'
-                               'map(attribute="name")|join("|") }}')
-        assert tmpl.render(users=users) == 'jane'
+        tmpl = env.from_string(
+            '{{ users|rejectattr("id", "odd")|map(attribute="name")|join("|") }}'
+        )
+        assert tmpl.render(users=users) == "jane"
 
     def test_json_dump(self):
         env = Environment(autoescape=True)
-        t = env.from_string('{{ x|tojson }}')
-        assert t.render(x={'foo': 'bar'}) == '{"foo": "bar"}'
-        assert t.render(x='"ba&r\'') == r'"\"ba\u0026r\u0027"'
-        assert t.render(x='<bar>') == r'"\u003cbar\u003e"'
+        t = env.from_string("{{ x|tojson }}")
+        assert t.render(x={"foo": "bar"}) == '{"foo": "bar"}'
+        assert t.render(x="\"ba&r'") == r'"\"ba\u0026r\u0027"'
+        assert t.render(x="<bar>") == r'"\u003cbar\u003e"'
 
         def my_dumps(value, **options):
-            assert options == {'foo': 'bar'}
-            return '42'
-        env.policies['json.dumps_function'] = my_dumps
-        env.policies['json.dumps_kwargs'] = {'foo': 'bar'}
-        assert t.render(x=23) == '42'
+            assert options == {"foo": "bar"}
+            return "42"
+
+        env.policies["json.dumps_function"] = my_dumps
+        env.policies["json.dumps_kwargs"] = {"foo": "bar"}
+        assert t.render(x=23) == "42"
 
     def test_wordwrap(self, env):
         env.newline_sequence = "\n"
index 29312d3e3d35dd391e3df78d410d0ec4fc3535db..4c79ee6c4718d2989821081de55e643f7deb72c4 100644 (file)
@@ -4,213 +4,286 @@ from jinja2.idtracking import symbols_for_node
 
 def test_basics():
     for_loop = nodes.For(
-        nodes.Name('foo', 'store'),
-        nodes.Name('seq', 'load'),
-        [nodes.Output([nodes.Name('foo', 'load')])],
-        [], None, False)
-    tmpl = nodes.Template([
-        nodes.Assign(
-            nodes.Name('foo', 'store'),
-            nodes.Name('bar', 'load')),
-        for_loop])
+        nodes.Name("foo", "store"),
+        nodes.Name("seq", "load"),
+        [nodes.Output([nodes.Name("foo", "load")])],
+        [],
+        None,
+        False,
+    )
+    tmpl = nodes.Template(
+        [nodes.Assign(nodes.Name("foo", "store"), nodes.Name("bar", "load")), for_loop]
+    )
 
     sym = symbols_for_node(tmpl)
     assert sym.refs == {
-        'foo': 'l_0_foo',
-        'bar': 'l_0_bar',
-        'seq': 'l_0_seq',
+        "foo": "l_0_foo",
+        "bar": "l_0_bar",
+        "seq": "l_0_seq",
     }
     assert sym.loads == {
-        'l_0_foo': ('undefined', None),
-        'l_0_bar': ('resolve', 'bar'),
-        'l_0_seq': ('resolve', 'seq'),
+        "l_0_foo": ("undefined", None),
+        "l_0_bar": ("resolve", "bar"),
+        "l_0_seq": ("resolve", "seq"),
     }
 
     sym = symbols_for_node(for_loop, sym)
     assert sym.refs == {
-        'foo': 'l_1_foo',
+        "foo": "l_1_foo",
     }
     assert sym.loads == {
-        'l_1_foo': ('param', None),
+        "l_1_foo": ("param", None),
     }
 
 
 def test_complex():
-    title_block = nodes.Block('title', [
-        nodes.Output([nodes.TemplateData(u'Page Title')])
-    ], False)
-
-    render_title_macro = nodes.Macro('render_title', [nodes.Name('title', 'param')], [], [
-        nodes.Output([
-            nodes.TemplateData(u'\n  <div class="title">\n    <h1>'),
-            nodes.Name('title', 'load'),
-            nodes.TemplateData(u'</h1>\n    <p>'),
-            nodes.Name('subtitle', 'load'),
-            nodes.TemplateData(u'</p>\n    ')]),
-        nodes.Assign(
-            nodes.Name('subtitle', 'store'), nodes.Const('something else')),
-        nodes.Output([
-            nodes.TemplateData(u'\n    <p>'),
-            nodes.Name('subtitle', 'load'),
-            nodes.TemplateData(u'</p>\n  </div>\n'),
-            nodes.If(
-                nodes.Name('something', 'load'), [
-                    nodes.Assign(nodes.Name('title_upper', 'store'),
-                                 nodes.Filter(nodes.Name('title', 'load'),
-                                              'upper', [], [], None, None)),
-                    nodes.Output([
-                        nodes.Name('title_upper', 'load'),
-                        nodes.Call(nodes.Name('render_title', 'load'), [
-                            nodes.Const('Aha')], [], None, None)])], [], [])])])
+    title_block = nodes.Block(
+        "title", [nodes.Output([nodes.TemplateData(u"Page Title")])], False
+    )
+
+    render_title_macro = nodes.Macro(
+        "render_title",
+        [nodes.Name("title", "param")],
+        [],
+        [
+            nodes.Output(
+                [
+                    nodes.TemplateData(u'\n  <div class="title">\n    <h1>'),
+                    nodes.Name("title", "load"),
+                    nodes.TemplateData(u"</h1>\n    <p>"),
+                    nodes.Name("subtitle", "load"),
+                    nodes.TemplateData(u"</p>\n    "),
+                ]
+            ),
+            nodes.Assign(
+                nodes.Name("subtitle", "store"), nodes.Const("something else")
+            ),
+            nodes.Output(
+                [
+                    nodes.TemplateData(u"\n    <p>"),
+                    nodes.Name("subtitle", "load"),
+                    nodes.TemplateData(u"</p>\n  </div>\n"),
+                    nodes.If(
+                        nodes.Name("something", "load"),
+                        [
+                            nodes.Assign(
+                                nodes.Name("title_upper", "store"),
+                                nodes.Filter(
+                                    nodes.Name("title", "load"),
+                                    "upper",
+                                    [],
+                                    [],
+                                    None,
+                                    None,
+                                ),
+                            ),
+                            nodes.Output(
+                                [
+                                    nodes.Name("title_upper", "load"),
+                                    nodes.Call(
+                                        nodes.Name("render_title", "load"),
+                                        [nodes.Const("Aha")],
+                                        [],
+                                        None,
+                                        None,
+                                    ),
+                                ]
+                            ),
+                        ],
+                        [],
+                        [],
+                    ),
+                ]
+            ),
+        ],
+    )
 
     for_loop = nodes.For(
-        nodes.Name('item', 'store'),
-        nodes.Name('seq', 'load'), [
-            nodes.Output([
-                nodes.TemplateData(u'\n    <li>'),
-                nodes.Name('item', 'load'),
-                nodes.TemplateData(u'</li>\n    <span>')]),
-            nodes.Include(nodes.Const('helper.html'), True, False),
-            nodes.Output([
-                nodes.TemplateData(u'</span>\n  ')])], [], None, False)
-
-    body_block = nodes.Block('body', [
-        nodes.Output([
-            nodes.TemplateData(u'\n  '),
-            nodes.Call(nodes.Name('render_title', 'load'), [
-                nodes.Name('item', 'load')], [], None, None),
-            nodes.TemplateData(u'\n  <ul>\n  ')]),
-        for_loop,
-        nodes.Output([nodes.TemplateData(u'\n  </ul>\n')])],
-        False)
-
-    tmpl = nodes.Template([
-        nodes.Extends(nodes.Const('layout.html')),
-        title_block,
-        render_title_macro,
-        body_block,
-    ])
+        nodes.Name("item", "store"),
+        nodes.Name("seq", "load"),
+        [
+            nodes.Output(
+                [
+                    nodes.TemplateData(u"\n    <li>"),
+                    nodes.Name("item", "load"),
+                    nodes.TemplateData(u"</li>\n    <span>"),
+                ]
+            ),
+            nodes.Include(nodes.Const("helper.html"), True, False),
+            nodes.Output([nodes.TemplateData(u"</span>\n  ")]),
+        ],
+        [],
+        None,
+        False,
+    )
+
+    body_block = nodes.Block(
+        "body",
+        [
+            nodes.Output(
+                [
+                    nodes.TemplateData(u"\n  "),
+                    nodes.Call(
+                        nodes.Name("render_title", "load"),
+                        [nodes.Name("item", "load")],
+                        [],
+                        None,
+                        None,
+                    ),
+                    nodes.TemplateData(u"\n  <ul>\n  "),
+                ]
+            ),
+            for_loop,
+            nodes.Output([nodes.TemplateData(u"\n  </ul>\n")]),
+        ],
+        False,
+    )
+
+    tmpl = nodes.Template(
+        [
+            nodes.Extends(nodes.Const("layout.html")),
+            title_block,
+            render_title_macro,
+            body_block,
+        ]
+    )
 
     tmpl_sym = symbols_for_node(tmpl)
     assert tmpl_sym.refs == {
-        'render_title': 'l_0_render_title',
+        "render_title": "l_0_render_title",
     }
     assert tmpl_sym.loads == {
-        'l_0_render_title': ('undefined', None),
+        "l_0_render_title": ("undefined", None),
     }
-    assert tmpl_sym.stores == set(['render_title'])
+    assert tmpl_sym.stores == set(["render_title"])
     assert tmpl_sym.dump_stores() == {
-        'render_title': 'l_0_render_title',
+        "render_title": "l_0_render_title",
     }
 
     macro_sym = symbols_for_node(render_title_macro, tmpl_sym)
     assert macro_sym.refs == {
-        'subtitle': 'l_1_subtitle',
-        'something': 'l_1_something',
-        'title': 'l_1_title',
-        'title_upper': 'l_1_title_upper',
+        "subtitle": "l_1_subtitle",
+        "something": "l_1_something",
+        "title": "l_1_title",
+        "title_upper": "l_1_title_upper",
     }
     assert macro_sym.loads == {
-        'l_1_subtitle': ('resolve', 'subtitle'),
-        'l_1_something': ('resolve','something'),
-        'l_1_title': ('param', None),
-        'l_1_title_upper': ('resolve', 'title_upper'),
+        "l_1_subtitle": ("resolve", "subtitle"),
+        "l_1_something": ("resolve", "something"),
+        "l_1_title": ("param", None),
+        "l_1_title_upper": ("resolve", "title_upper"),
     }
-    assert macro_sym.stores == set(['title', 'title_upper', 'subtitle'])
-    assert macro_sym.find_ref('render_title') == 'l_0_render_title'
+    assert macro_sym.stores == set(["title", "title_upper", "subtitle"])
+    assert macro_sym.find_ref("render_title") == "l_0_render_title"
     assert macro_sym.dump_stores() == {
-        'title': 'l_1_title',
-        'title_upper': 'l_1_title_upper',
-        'subtitle': 'l_1_subtitle',
-        'render_title': 'l_0_render_title',
+        "title": "l_1_title",
+        "title_upper": "l_1_title_upper",
+        "subtitle": "l_1_subtitle",
+        "render_title": "l_0_render_title",
     }
 
     body_sym = symbols_for_node(body_block)
     assert body_sym.refs == {
-        'item': 'l_0_item',
-        'seq': 'l_0_seq',
-        'render_title': 'l_0_render_title',
+        "item": "l_0_item",
+        "seq": "l_0_seq",
+        "render_title": "l_0_render_title",
     }
     assert body_sym.loads == {
-        'l_0_item': ('resolve', 'item'),
-        'l_0_seq': ('resolve', 'seq'),
-        'l_0_render_title': ('resolve', 'render_title'),
+        "l_0_item": ("resolve", "item"),
+        "l_0_seq": ("resolve", "seq"),
+        "l_0_render_title": ("resolve", "render_title"),
     }
     assert body_sym.stores == set([])
 
     for_sym = symbols_for_node(for_loop, body_sym)
     assert for_sym.refs == {
-        'item': 'l_1_item',
+        "item": "l_1_item",
     }
     assert for_sym.loads == {
-        'l_1_item': ('param', None),
+        "l_1_item": ("param", None),
     }
-    assert for_sym.stores == set(['item'])
+    assert for_sym.stores == set(["item"])
     assert for_sym.dump_stores() == {
-        'item': 'l_1_item',
+        "item": "l_1_item",
     }
 
 
 def test_if_branching_stores():
-    tmpl = nodes.Template([
-        nodes.If(nodes.Name('expression', 'load'), [
-            nodes.Assign(nodes.Name('variable', 'store'),
-                         nodes.Const(42))], [], [])])
+    tmpl = nodes.Template(
+        [
+            nodes.If(
+                nodes.Name("expression", "load"),
+                [nodes.Assign(nodes.Name("variable", "store"), nodes.Const(42))],
+                [],
+                [],
+            )
+        ]
+    )
 
     sym = symbols_for_node(tmpl)
-    assert sym.refs == {
-        'variable': 'l_0_variable',
-        'expression': 'l_0_expression'
-    }
-    assert sym.stores == set(['variable'])
+    assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
+    assert sym.stores == set(["variable"])
     assert sym.loads == {
-        'l_0_variable': ('resolve', 'variable'),
-        'l_0_expression': ('resolve', 'expression')
+        "l_0_variable": ("resolve", "variable"),
+        "l_0_expression": ("resolve", "expression"),
     }
     assert sym.dump_stores() == {
-        'variable': 'l_0_variable',
+        "variable": "l_0_variable",
     }
 
 
 def test_if_branching_stores_undefined():
-    tmpl = nodes.Template([
-        nodes.Assign(nodes.Name('variable', 'store'), nodes.Const(23)),
-        nodes.If(nodes.Name('expression', 'load'), [
-            nodes.Assign(nodes.Name('variable', 'store'),
-                         nodes.Const(42))], [], [])])
+    tmpl = nodes.Template(
+        [
+            nodes.Assign(nodes.Name("variable", "store"), nodes.Const(23)),
+            nodes.If(
+                nodes.Name("expression", "load"),
+                [nodes.Assign(nodes.Name("variable", "store"), nodes.Const(42))],
+                [],
+                [],
+            ),
+        ]
+    )
 
     sym = symbols_for_node(tmpl)
-    assert sym.refs == {
-        'variable': 'l_0_variable',
-        'expression': 'l_0_expression'
-    }
-    assert sym.stores == set(['variable'])
+    assert sym.refs == {"variable": "l_0_variable", "expression": "l_0_expression"}
+    assert sym.stores == set(["variable"])
     assert sym.loads == {
-        'l_0_variable': ('undefined', None),
-        'l_0_expression': ('resolve', 'expression')
+        "l_0_variable": ("undefined", None),
+        "l_0_expression": ("resolve", "expression"),
     }
     assert sym.dump_stores() == {
-        'variable': 'l_0_variable',
+        "variable": "l_0_variable",
     }
 
 
 def test_if_branching_multi_scope():
-    for_loop = nodes.For(nodes.Name('item', 'store'), nodes.Name('seq', 'load'), [
-        nodes.If(nodes.Name('expression', 'load'), [
-            nodes.Assign(nodes.Name('x', 'store'), nodes.Const(42))], [], []),
-        nodes.Include(nodes.Const('helper.html'), True, False)
-    ], [], None, False)
+    for_loop = nodes.For(
+        nodes.Name("item", "store"),
+        nodes.Name("seq", "load"),
+        [
+            nodes.If(
+                nodes.Name("expression", "load"),
+                [nodes.Assign(nodes.Name("x", "store"), nodes.Const(42))],
+                [],
+                [],
+            ),
+            nodes.Include(nodes.Const("helper.html"), True, False),
+        ],
+        [],
+        None,
+        False,
+    )
 
-    tmpl = nodes.Template([
-        nodes.Assign(nodes.Name('x', 'store'), nodes.Const(23)),
-        for_loop
-    ])
+    tmpl = nodes.Template(
+        [nodes.Assign(nodes.Name("x", "store"), nodes.Const(23)), for_loop]
+    )
 
     tmpl_sym = symbols_for_node(tmpl)
     for_sym = symbols_for_node(for_loop, tmpl_sym)
-    assert for_sym.stores == set(['item', 'x'])
+    assert for_sym.stores == set(["item", "x"])
     assert for_sym.loads == {
-        'l_1_x': ('alias', 'l_0_x'),
-        'l_1_item': ('param', None),
-        'l_1_expression': ('resolve', 'expression'),
+        "l_1_x": ("alias", "l_0_x"),
+        "l_1_item": ("param", None),
+        "l_1_expression": ("resolve", "expression"),
     }
index 2224fb8bc7ecead3723017a2fad414c691d2c939..f2895d6682f291f9283f1046c3176318a8bd44c8 100644 (file)
@@ -19,39 +19,42 @@ from jinja2.exceptions import TemplateSyntaxError
 
 @pytest.fixture
 def test_env():
-    env = Environment(loader=DictLoader(dict(
-        module='{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}',
-        header='[{{ foo }}|{{ 23 }}]',
-        o_printer='({{ o }})'
-    )))
-    env.globals['bar'] = 23
+    env = Environment(
+        loader=DictLoader(
+            dict(
+                module="{% macro test() %}[{{ foo }}|{{ bar }}]{% endmacro %}",
+                header="[{{ foo }}|{{ 23 }}]",
+                o_printer="({{ o }})",
+            )
+        )
+    )
+    env.globals["bar"] = 23
     return env
 
 
 @pytest.mark.imports
 class TestImports(object):
-
     def test_context_imports(self, test_env):
         t = test_env.from_string('{% import "module" as m %}{{ m.test() }}')
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env.from_string(
             '{% import "module" as m without context %}{{ m.test() }}'
         )
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env.from_string(
             '{% import "module" as m with context %}{{ m.test() }}'
         )
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
         t = test_env.from_string('{% from "module" import test %}{{ test() }}')
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env.from_string(
             '{% from "module" import test without context %}{{ test() }}'
         )
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
         t = test_env.from_string(
             '{% from "module" import test with context %}{{ test() }}'
         )
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
 
     def test_import_needs_name(self, test_env):
         test_env.from_string('{% from "foo" import bar %}')
@@ -84,81 +87,86 @@ class TestImports(object):
             test_env.from_string('{% from "foo" import bar with context, %}')
 
     def test_exports(self, test_env):
-        m = test_env.from_string('''
+        m = test_env.from_string(
+            """
             {% macro toplevel() %}...{% endmacro %}
             {% macro __private() %}...{% endmacro %}
             {% set variable = 42 %}
             {% for item in [1] %}
                 {% macro notthere() %}{% endmacro %}
             {% endfor %}
-        ''').module
-        assert m.toplevel() == '...'
-        assert not hasattr(m, '__missing')
+        """
+        ).module
+        assert m.toplevel() == "..."
+        assert not hasattr(m, "__missing")
         assert m.variable == 42
-        assert not hasattr(m, 'notthere')
+        assert not hasattr(m, "notthere")
 
 
 @pytest.mark.imports
 @pytest.mark.includes
 class TestIncludes(object):
-
     def test_context_include(self, test_env):
         t = test_env.from_string('{% include "header" %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
         t = test_env.from_string('{% include "header" with context %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
         t = test_env.from_string('{% include "header" without context %}')
-        assert t.render(foo=42) == '[|23]'
+        assert t.render(foo=42) == "[|23]"
 
     def test_choice_includes(self, test_env):
         t = test_env.from_string('{% include ["missing", "header"] %}')
-        assert t.render(foo=42) == '[42|23]'
+        assert t.render(foo=42) == "[42|23]"
 
-        t = test_env.from_string(
-            '{% include ["missing", "missing2"] ignore missing %}'
-        )
-        assert t.render(foo=42) == ''
+        t = test_env.from_string('{% include ["missing", "missing2"] ignore missing %}')
+        assert t.render(foo=42) == ""
 
         t = test_env.from_string('{% include ["missing", "missing2"] %}')
         pytest.raises(TemplateNotFound, t.render)
         with pytest.raises(TemplatesNotFound) as e:
             t.render()
 
-        assert e.value.templates == ['missing', 'missing2']
-        assert e.value.name == 'missing2'
+        assert e.value.templates == ["missing", "missing2"]
+        assert e.value.name == "missing2"
 
         def test_includes(t, **ctx):
-            ctx['foo'] = 42
-            assert t.render(ctx) == '[42|23]'
+            ctx["foo"] = 42
+            assert t.render(ctx) == "[42|23]"
 
         t = test_env.from_string('{% include ["missing", "header"] %}')
         test_includes(t)
-        t = test_env.from_string('{% include x %}')
-        test_includes(t, x=['missing', 'header'])
+        t = test_env.from_string("{% include x %}")
+        test_includes(t, x=["missing", "header"])
         t = test_env.from_string('{% include [x, "header"] %}')
-        test_includes(t, x='missing')
-        t = test_env.from_string('{% include x %}')
-        test_includes(t, x='header')
-        t = test_env.from_string('{% include [x] %}')
-        test_includes(t, x='header')
+        test_includes(t, x="missing")
+        t = test_env.from_string("{% include x %}")
+        test_includes(t, x="header")
+        t = test_env.from_string("{% include [x] %}")
+        test_includes(t, x="header")
 
     def test_include_ignoring_missing(self, test_env):
         t = test_env.from_string('{% include "missing" %}')
         pytest.raises(TemplateNotFound, t.render)
-        for extra in '', 'with context', 'without context':
-            t = test_env.from_string('{% include "missing" ignore missing ' +
-                                     extra + ' %}')
-            assert t.render() == ''
+        for extra in "", "with context", "without context":
+            t = test_env.from_string(
+                '{% include "missing" ignore missing ' + extra + " %}"
+            )
+            assert t.render() == ""
 
     def test_context_include_with_overrides(self, test_env):
-        env = Environment(loader=DictLoader(dict(
-            main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
-            item="{{ item }}"
-        )))
+        env = Environment(
+            loader=DictLoader(
+                dict(
+                    main="{% for item in [1, 2, 3] %}{% include 'item' %}{% endfor %}",
+                    item="{{ item }}",
+                )
+            )
+        )
         assert env.get_template("main").render() == "123"
 
     def test_unoptimized_scopes(self, test_env):
-        t = test_env.from_string("""
+        t = test_env.from_string(
+            """
             {% macro outer(o) %}
             {% macro inner() %}
             {% include "o_printer" %}
@@ -166,13 +174,15 @@ class TestIncludes(object):
             {{ inner() }}
             {% endmacro %}
             {{ outer("FOO") }}
-        """)
-        assert t.render().strip() == '(FOO)'
+        """
+        )
+        assert t.render().strip() == "(FOO)"
 
     def test_import_from_with_context(self):
-        env = Environment(loader=DictLoader({
-            'a': '{% macro x() %}{{ foobar }}{% endmacro %}',
-        }))
-        t = env.from_string('{% set foobar = 42 %}{% from "a" '
-                            'import x with context %}{{ x() }}')
-        assert t.render() == '42'
+        env = Environment(
+            loader=DictLoader({"a": "{% macro x() %}{{ foobar }}{% endmacro %}",})
+        )
+        t = env.from_string(
+            '{% set foobar = 42 %}{% from "a" ' "import x with context %}{{ x() }}"
+        )
+        assert t.render() == "42"
index 32df3409b88260af564d4b98525695216cfcd8ec..6d44d4f2bb906fa6b27d774084a47690cb31eca6 100644 (file)
@@ -15,34 +15,34 @@ from jinja2 import Environment
 from jinja2 import TemplateError
 from jinja2 import TemplateRuntimeError
 
-LAYOUTTEMPLATE = '''\
+LAYOUTTEMPLATE = """\
 |{% block block1 %}block 1 from layout{% endblock %}
 |{% block block2 %}block 2 from layout{% endblock %}
 |{% block block3 %}
 {% block block4 %}nested block 4 from layout{% endblock %}
-{% endblock %}|'''
+{% endblock %}|"""
 
-LEVEL1TEMPLATE = '''\
+LEVEL1TEMPLATE = """\
 {% extends "layout" %}
-{% block block1 %}block 1 from level1{% endblock %}'''
+{% block block1 %}block 1 from level1{% endblock %}"""
 
-LEVEL2TEMPLATE = '''\
+LEVEL2TEMPLATE = """\
 {% extends "level1" %}
 {% block block2 %}{% block block5 %}nested block 5 from level2{%
-endblock %}{% endblock %}'''
+endblock %}{% endblock %}"""
 
-LEVEL3TEMPLATE = '''\
+LEVEL3TEMPLATE = """\
 {% extends "level2" %}
 {% block block5 %}block 5 from level3{% endblock %}
 {% block block4 %}block 4 from level3{% endblock %}
-'''
+"""
 
-LEVEL4TEMPLATE = '''\
+LEVEL4TEMPLATE = """\
 {% extends "level3" %}
 {% block block3 %}block 3 from level4{% endblock %}
-'''
+"""
 
-WORKINGTEMPLATE = '''\
+WORKINGTEMPLATE = """\
 {% extends "layout" %}
 {% block block1 %}
   {% if false %}
@@ -51,9 +51,9 @@ WORKINGTEMPLATE = '''\
     {% endblock %}
   {% endif %}
 {% endblock %}
-'''
+"""
 
-DOUBLEEXTENDS = '''\
+DOUBLEEXTENDS = """\
 {% extends "layout" %}
 {% extends "layout" %}
 {% block block1 %}
@@ -63,127 +63,166 @@ DOUBLEEXTENDS = '''\
     {% endblock %}
   {% endif %}
 {% endblock %}
-'''
+"""
 
 
 @pytest.fixture
 def env():
-    return Environment(loader=DictLoader({
-        'layout':       LAYOUTTEMPLATE,
-        'level1':       LEVEL1TEMPLATE,
-        'level2':       LEVEL2TEMPLATE,
-        'level3':       LEVEL3TEMPLATE,
-        'level4':       LEVEL4TEMPLATE,
-        'working':      WORKINGTEMPLATE,
-        'doublee':      DOUBLEEXTENDS,
-    }), trim_blocks=True)
+    return Environment(
+        loader=DictLoader(
+            {
+                "layout": LAYOUTTEMPLATE,
+                "level1": LEVEL1TEMPLATE,
+                "level2": LEVEL2TEMPLATE,
+                "level3": LEVEL3TEMPLATE,
+                "level4": LEVEL4TEMPLATE,
+                "working": WORKINGTEMPLATE,
+                "doublee": DOUBLEEXTENDS,
+            }
+        ),
+        trim_blocks=True,
+    )
 
 
 @pytest.mark.inheritance
 class TestInheritance(object):
-
     def test_layout(self, env):
-        tmpl = env.get_template('layout')
-        assert tmpl.render() == ('|block 1 from layout|block 2 from '
-                                 'layout|nested block 4 from layout|')
+        tmpl = env.get_template("layout")
+        assert tmpl.render() == (
+            "|block 1 from layout|block 2 from layout|nested block 4 from layout|"
+        )
 
     def test_level1(self, env):
-        tmpl = env.get_template('level1')
-        assert tmpl.render() == ('|block 1 from level1|block 2 from '
-                                 'layout|nested block 4 from layout|')
+        tmpl = env.get_template("level1")
+        assert tmpl.render() == (
+            "|block 1 from level1|block 2 from layout|nested block 4 from layout|"
+        )
 
     def test_level2(self, env):
-        tmpl = env.get_template('level2')
-        assert tmpl.render() == ('|block 1 from level1|nested block 5 from '
-                                 'level2|nested block 4 from layout|')
+        tmpl = env.get_template("level2")
+        assert tmpl.render() == (
+            "|block 1 from level1|nested block 5 from "
+            "level2|nested block 4 from layout|"
+        )
 
     def test_level3(self, env):
-        tmpl = env.get_template('level3')
-        assert tmpl.render() == ('|block 1 from level1|block 5 from level3|'
-                                 'block 4 from level3|')
+        tmpl = env.get_template("level3")
+        assert tmpl.render() == (
+            "|block 1 from level1|block 5 from level3|block 4 from level3|"
+        )
 
     def test_level4(self, env):
-        tmpl = env.get_template('level4')
-        assert tmpl.render() == ('|block 1 from level1|block 5 from '
-                                 'level3|block 3 from level4|')
+        tmpl = env.get_template("level4")
+        assert tmpl.render() == (
+            "|block 1 from level1|block 5 from level3|block 3 from level4|"
+        )
 
     def test_super(self, env):
-        env = Environment(loader=DictLoader({
-            'a': '{% block intro %}INTRO{% endblock %}|'
-                 'BEFORE|{% block data %}INNER{% endblock %}|AFTER',
-            'b': '{% extends "a" %}{% block data %}({{ '
-                 'super() }}){% endblock %}',
-            'c': '{% extends "b" %}{% block intro %}--{{ '
-                 'super() }}--{% endblock %}\n{% block data '
-                 '%}[{{ super() }}]{% endblock %}'
-        }))
-        tmpl = env.get_template('c')
-        assert tmpl.render() == '--INTRO--|BEFORE|[(INNER)]|AFTER'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "a": "{% block intro %}INTRO{% endblock %}|"
+                    "BEFORE|{% block data %}INNER{% endblock %}|AFTER",
+                    "b": '{% extends "a" %}{% block data %}({{ '
+                    "super() }}){% endblock %}",
+                    "c": '{% extends "b" %}{% block intro %}--{{ '
+                    "super() }}--{% endblock %}\n{% block data "
+                    "%}[{{ super() }}]{% endblock %}",
+                }
+            )
+        )
+        tmpl = env.get_template("c")
+        assert tmpl.render() == "--INTRO--|BEFORE|[(INNER)]|AFTER"
 
     def test_working(self, env):
-        tmpl = env.get_template('working')
+        tmpl = env.get_template("working")
 
     def test_reuse_blocks(self, env):
-        tmpl = env.from_string('{{ self.foo() }}|{% block foo %}42'
-                               '{% endblock %}|{{ self.foo() }}')
-        assert tmpl.render() == '42|42|42'
+        tmpl = env.from_string(
+            "{{ self.foo() }}|{% block foo %}42{% endblock %}|{{ self.foo() }}"
+        )
+        assert tmpl.render() == "42|42|42"
 
     def test_preserve_blocks(self, env):
-        env = Environment(loader=DictLoader({
-            'a': '{% if false %}{% block x %}A{% endblock %}'
-            '{% endif %}{{ self.x() }}',
-            'b': '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}'
-        }))
-        tmpl = env.get_template('b')
-        assert tmpl.render() == 'BA'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "a": "{% if false %}{% block x %}A{% endblock %}"
+                    "{% endif %}{{ self.x() }}",
+                    "b": '{% extends "a" %}{% block x %}B{{ super() }}{% endblock %}',
+                }
+            )
+        )
+        tmpl = env.get_template("b")
+        assert tmpl.render() == "BA"
 
     def test_dynamic_inheritance(self, env):
-        env = Environment(loader=DictLoader({
-            'master1': 'MASTER1{% block x %}{% endblock %}',
-            'master2': 'MASTER2{% block x %}{% endblock %}',
-            'child': '{% extends master %}{% block x %}CHILD{% endblock %}'
-        }))
-        tmpl = env.get_template('child')
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "master1": "MASTER1{% block x %}{% endblock %}",
+                    "master2": "MASTER2{% block x %}{% endblock %}",
+                    "child": "{% extends master %}{% block x %}CHILD{% endblock %}",
+                }
+            )
+        )
+        tmpl = env.get_template("child")
         for m in range(1, 3):
-            assert tmpl.render(master='master%d' % m) == 'MASTER%dCHILD' % m
+            assert tmpl.render(master="master%d" % m) == "MASTER%dCHILD" % m
 
     def test_multi_inheritance(self, env):
-        env = Environment(loader=DictLoader({
-            'master1': 'MASTER1{% block x %}{% endblock %}',
-            'master2': 'MASTER2{% block x %}{% endblock %}',
-            'child':
-                '''{% if master %}{% extends master %}{% else %}{% extends
-                'master1' %}{% endif %}{% block x %}CHILD{% endblock %}'''
-        }))
-        tmpl = env.get_template('child')
-        assert tmpl.render(master='master2') == 'MASTER2CHILD'
-        assert tmpl.render(master='master1') == 'MASTER1CHILD'
-        assert tmpl.render() == 'MASTER1CHILD'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "master1": "MASTER1{% block x %}{% endblock %}",
+                    "master2": "MASTER2{% block x %}{% endblock %}",
+                    "child": """{% if master %}{% extends master %}{% else %}{% extends
+                'master1' %}{% endif %}{% block x %}CHILD{% endblock %}""",
+                }
+            )
+        )
+        tmpl = env.get_template("child")
+        assert tmpl.render(master="master2") == "MASTER2CHILD"
+        assert tmpl.render(master="master1") == "MASTER1CHILD"
+        assert tmpl.render() == "MASTER1CHILD"
 
     def test_scoped_block(self, env):
-        env = Environment(loader=DictLoader({
-            'master.html': '{% for item in seq %}[{% block item scoped %}'
-                           '{% endblock %}]{% endfor %}'
-        }))
-        t = env.from_string('{% extends "master.html" %}{% block item %}'
-                            '{{ item }}{% endblock %}')
-        assert t.render(seq=list(range(5))) == '[0][1][2][3][4]'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "master.html": "{% for item in seq %}[{% block item scoped %}"
+                    "{% endblock %}]{% endfor %}"
+                }
+            )
+        )
+        t = env.from_string(
+            '{% extends "master.html" %}{% block item %}' "{{ item }}{% endblock %}"
+        )
+        assert t.render(seq=list(range(5))) == "[0][1][2][3][4]"
 
     def test_super_in_scoped_block(self, env):
-        env = Environment(loader=DictLoader({
-            'master.html': '{% for item in seq %}[{% block item scoped %}'
-                           '{{ item }}{% endblock %}]{% endfor %}'
-        }))
-        t = env.from_string('{% extends "master.html" %}{% block item %}'
-                            '{{ super() }}|{{ item * 2 }}{% endblock %}')
-        assert t.render(seq=list(range(5))) == '[0|0][1|2][2|4][3|6][4|8]'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "master.html": "{% for item in seq %}[{% block item scoped %}"
+                    "{{ item }}{% endblock %}]{% endfor %}"
+                }
+            )
+        )
+        t = env.from_string(
+            '{% extends "master.html" %}{% block item %}'
+            "{{ super() }}|{{ item * 2 }}{% endblock %}"
+        )
+        assert t.render(seq=list(range(5))) == "[0|0][1|2][2|4][3|6][4|8]"
 
     def test_scoped_block_after_inheritance(self, env):
-        env = Environment(loader=DictLoader({
-            'layout.html': '''
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "layout.html": """
             {% block useless %}{% endblock %}
-            ''',
-            'index.html': '''
+            """,
+                    "index.html": """
             {%- extends 'layout.html' %}
             {% from 'helpers.html' import foo with context %}
             {% block useless %}
@@ -193,21 +232,25 @@ class TestInheritance(object):
                     {% endblock %}
                 {% endfor %}
             {% endblock %}
-            ''',
-            'helpers.html': '''
+            """,
+                    "helpers.html": """
             {% macro foo(x) %}{{ the_foo + x }}{% endmacro %}
-            '''
-        }))
-        rv = env.get_template('index.html').render(the_foo=42).split()
-        assert rv == ['43', '44', '45']
+            """,
+                }
+            )
+        )
+        rv = env.get_template("index.html").render(the_foo=42).split()
+        assert rv == ["43", "44", "45"]
 
 
 @pytest.mark.inheritance
 class TestBugFix(object):
-
     def test_fixed_macro_scoping_bug(self, env):
-        assert Environment(loader=DictLoader({
-            'test.html': '''\
+        assert (
+            Environment(
+                loader=DictLoader(
+                    {
+                        "test.html": """\
         {% extends 'details.html' %}
 
         {% macro my_macro() %}
@@ -217,8 +260,8 @@ class TestBugFix(object):
         {% block inner_box %}
             {{ my_macro() }}
         {% endblock %}
-            ''',
-            'details.html': '''\
+            """,
+                        "details.html": """\
         {% extends 'standard.html' %}
 
         {% macro my_macro() %}
@@ -233,16 +276,22 @@ class TestBugFix(object):
                 {% endblock %}
             {% endblock %}
         {% endblock %}
-        ''',
-            'standard.html': '''
+        """,
+                        "standard.html": """
         {% block content %}&nbsp;{% endblock %}
-        '''
-        })).get_template("test.html").render().split() \
-            == [u'outer_box', u'my_macro']
+        """,
+                    }
+                )
+            )
+            .get_template("test.html")
+            .render()
+            .split()
+            == [u"outer_box", u"my_macro"]
+        )
 
     def test_double_extends(self, env):
         """Ensures that a template with more than 1 {% extends ... %} usage
         raises a ``TemplateError``.
         """
         with pytest.raises(TemplateRuntimeError, match="extended multiple times"):
-            env.get_template('doublee').render()
+            env.get_template("doublee").render()
index a7ef46a2f14b188c3fabd7bad2d4723c2c113f5f..fb54ac8f72762f6624e80ee3d3ec6b62ace3c0a1 100644 (file)
@@ -27,8 +27,11 @@ from jinja2.lexer import TokenStream
 
 # how does a string look like in jinja syntax?
 if PY2:
+
     def jinja_string_repr(string):
         return repr(string)[1:]
+
+
 else:
     jinja_string_repr = repr
 
@@ -36,9 +39,10 @@ else:
 @pytest.mark.lexnparse
 @pytest.mark.tokenstream
 class TestTokenStream(object):
-    test_tokens = [Token(1, TOKEN_BLOCK_BEGIN, ''),
-                   Token(2, TOKEN_BLOCK_END, ''),
-                   ]
+    test_tokens = [
+        Token(1, TOKEN_BLOCK_BEGIN, ""),
+        Token(2, TOKEN_BLOCK_END, ""),
+    ]
 
     def test_simple(self, env):
         ts = TokenStream(self.test_tokens, "foo", "bar")
@@ -55,117 +59,129 @@ class TestTokenStream(object):
         assert bool(ts.eos)
 
     def test_iter(self, env):
-        token_types = [
-            t.type for t in TokenStream(self.test_tokens, "foo", "bar")
+        token_types = [t.type for t in TokenStream(self.test_tokens, "foo", "bar")]
+        assert token_types == [
+            "block_begin",
+            "block_end",
         ]
-        assert token_types == ['block_begin', 'block_end', ]
 
 
 @pytest.mark.lexnparse
 @pytest.mark.lexer
 class TestLexer(object):
-
     def test_raw1(self, env):
         tmpl = env.from_string(
-            '{% raw %}foo{% endraw %}|'
-            '{%raw%}{{ bar }}|{% baz %}{%       endraw    %}')
-        assert tmpl.render() == 'foo|{{ bar }}|{% baz %}'
+            "{% raw %}foo{% endraw %}|"
+            "{%raw%}{{ bar }}|{% baz %}{%       endraw    %}"
+        )
+        assert tmpl.render() == "foo|{{ bar }}|{% baz %}"
 
     def test_raw2(self, env):
-        tmpl = env.from_string('1  {%- raw -%}   2   {%- endraw -%}   3')
-        assert tmpl.render() == '123'
+        tmpl = env.from_string("1  {%- raw -%}   2   {%- endraw -%}   3")
+        assert tmpl.render() == "123"
 
     def test_raw3(self, env):
         # The second newline after baz exists because it is AFTER the {% raw %} and is ignored.
         env = Environment(lstrip_blocks=True, trim_blocks=True)
         tmpl = env.from_string("bar\n{% raw %}\n  {{baz}}2 spaces\n{% endraw %}\nfoo")
-        assert tmpl.render(baz='test') == "bar\n\n  {{baz}}2 spaces\nfoo"
+        assert tmpl.render(baz="test") == "bar\n\n  {{baz}}2 spaces\nfoo"
 
     def test_raw4(self, env):
         # The trailing dash of the {% raw -%} cleans both the spaces and newlines up to the first character of data.
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string("bar\n{%- raw -%}\n\n  \n  2 spaces\n space{%- endraw -%}\nfoo")
+        tmpl = env.from_string(
+            "bar\n{%- raw -%}\n\n  \n  2 spaces\n space{%- endraw -%}\nfoo"
+        )
         assert tmpl.render() == "bar2 spaces\n spacefoo"
 
     def test_balancing(self, env):
-        env = Environment('{%', '%}', '${', '}')
-        tmpl = env.from_string('''{% for item in seq
-            %}${{'foo': item}|upper}{% endfor %}''')
-        assert tmpl.render(seq=list(range(3))) \
-            == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
+        env = Environment("{%", "%}", "${", "}")
+        tmpl = env.from_string(
+            """{% for item in seq
+            %}${{'foo': item}|upper}{% endfor %}"""
+        )
+        assert tmpl.render(seq=list(range(3))) == "{'FOO': 0}{'FOO': 1}{'FOO': 2}"
 
     def test_comments(self, env):
-        env = Environment('<!--', '-->', '{', '}')
-        tmpl = env.from_string('''\
+        env = Environment("<!--", "-->", "{", "}")
+        tmpl = env.from_string(
+            """\
 <ul>
 <!--- for item in seq -->
   <li>{item}</li>
 <!--- endfor -->
-</ul>''')
-        assert tmpl.render(seq=list(range(3))) \
-            == ("<ul>\n  <li>0</li>\n  ""<li>1</li>\n  <li>2</li>\n</ul>")
+</ul>"""
+        )
+        assert tmpl.render(seq=list(range(3))) == (
+            "<ul>\n  <li>0</li>\n  <li>1</li>\n  <li>2</li>\n</ul>"
+        )
 
     def test_string_escapes(self, env):
-        for char in u'\0', u'\u2668', u'\xe4', u'\t', u'\r', u'\n':
-            tmpl = env.from_string('{{ %s }}' % jinja_string_repr(char))
+        for char in u"\0", u"\u2668", u"\xe4", u"\t", u"\r", u"\n":
+            tmpl = env.from_string("{{ %s }}" % jinja_string_repr(char))
             assert tmpl.render() == char
-        assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u'\u2668'
+        assert env.from_string('{{ "\N{HOT SPRINGS}" }}').render() == u"\u2668"
 
     def test_bytefallback(self, env):
         from pprint import pformat
-        tmpl = env.from_string(u'''{{ 'foo'|pprint }}|{{ 'bär'|pprint }}''')
-        assert tmpl.render() == pformat('foo') + '|' + pformat(u'bär')
+
+        tmpl = env.from_string(u"""{{ 'foo'|pprint }}|{{ 'bär'|pprint }}""")
+        assert tmpl.render() == pformat("foo") + "|" + pformat(u"bär")
 
     def test_operators(self, env):
         from jinja2.lexer import operators
+
         for test, expect in iteritems(operators):
-            if test in '([{}])':
+            if test in "([{}])":
                 continue
-            stream = env.lexer.tokenize('{{ %s }}' % test)
+            stream = env.lexer.tokenize("{{ %s }}" % test)
             next(stream)
             assert stream.current.type == expect
 
     def test_normalizing(self, env):
-        for seq in '\r', '\r\n', '\n':
+        for seq in "\r", "\r\n", "\n":
             env = Environment(newline_sequence=seq)
-            tmpl = env.from_string('1\n2\r\n3\n4\n')
+            tmpl = env.from_string("1\n2\r\n3\n4\n")
             result = tmpl.render()
-            assert result.replace(seq, 'X') == '1X2X3X4'
+            assert result.replace(seq, "X") == "1X2X3X4"
 
     def test_trailing_newline(self, env):
         for keep in [True, False]:
             env = Environment(keep_trailing_newline=keep)
             for template, expected in [
-                    ('', {}),
-                    ('no\nnewline', {}),
-                    ('with\nnewline\n', {False: 'with\nnewline'}),
-                    ('with\nseveral\n\n\n', {False: 'with\nseveral\n\n'}),
-                    ]:
+                ("", {}),
+                ("no\nnewline", {}),
+                ("with\nnewline\n", {False: "with\nnewline"}),
+                ("with\nseveral\n\n\n", {False: "with\nseveral\n\n"}),
+            ]:
                 tmpl = env.from_string(template)
                 expect = expected.get(keep, template)
                 result = tmpl.render()
                 assert result == expect, (keep, template, result, expect)
 
-    @pytest.mark.parametrize('name,valid2,valid3', (
-        (u'foo', True, True),
-        (u'föö', False, True),
-        (u'き', False, True),
-        (u'_', True, True),
-        (u'1a', False, False),  # invalid ascii start
-        (u'a-', False, False),  # invalid ascii continue
-        (u'🐍', False, False),  # invalid unicode start
-        (u'a🐍', False, False),  # invalid unicode continue
-        # start characters not matched by \w
-        (u'\u1885', False, True),
-        (u'\u1886', False, True),
-        (u'\u2118', False, True),
-        (u'\u212e', False, True),
-        # continue character not matched by \w
-        (u'\xb7', False, False),
-        (u'a\xb7', False, True),
-    ))
+    @pytest.mark.parametrize(
+        "name,valid2,valid3",
+        (
+            (u"foo", True, True),
+            (u"föö", False, True),
+            (u"き", False, True),
+            (u"_", True, True),
+            (u"1a", False, False),  # invalid ascii start
+            (u"a-", False, False),  # invalid ascii continue
+            (u"🐍", False, False),  # invalid unicode start
+            (u"a🐍", False, False),  # invalid unicode continue
+            # start characters not matched by \w
+            (u"\u1885", False, True),
+            (u"\u1886", False, True),
+            (u"\u2118", False, True),
+            (u"\u212e", False, True),
+            # continue character not matched by \w
+            (u"\xb7", False, False),
+            (u"a\xb7", False, True),
+        ),
+    )
     def test_name(self, env, name, valid2, valid3):
-        t = u'{{ ' + name + u' }}'
+        t = u"{{ " + name + u" }}"
 
         if (valid2 and PY2) or (valid3 and not PY2):
             # valid for version being tested, shouldn't raise
@@ -177,159 +193,178 @@ class TestLexer(object):
 @pytest.mark.lexnparse
 @pytest.mark.parser
 class TestParser(object):
-
     def test_php_syntax(self, env):
-        env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->')
-        tmpl = env.from_string('''\
+        env = Environment("<?", "?>", "<?=", "?>", "<!--", "-->")
+        tmpl = env.from_string(
+            """\
 <!-- I'm a comment, I'm not interesting -->\
 <? for item in seq -?>
     <?= item ?>
-<?- endfor ?>''')
-        assert tmpl.render(seq=list(range(5))) == '01234'
+<?- endfor ?>"""
+        )
+        assert tmpl.render(seq=list(range(5))) == "01234"
 
     def test_erb_syntax(self, env):
-        env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>')
-        tmpl = env.from_string('''\
+        env = Environment("<%", "%>", "<%=", "%>", "<%#", "%>")
+        tmpl = env.from_string(
+            """\
 <%# I'm a comment, I'm not interesting %>\
 <% for item in seq -%>
     <%= item %>
-<%- endfor %>''')
-        assert tmpl.render(seq=list(range(5))) == '01234'
+<%- endfor %>"""
+        )
+        assert tmpl.render(seq=list(range(5))) == "01234"
 
     def test_comment_syntax(self, env):
-        env = Environment('<!--', '-->', '${', '}', '<!--#', '-->')
-        tmpl = env.from_string('''\
+        env = Environment("<!--", "-->", "${", "}", "<!--#", "-->")
+        tmpl = env.from_string(
+            """\
 <!--# I'm a comment, I'm not interesting -->\
 <!-- for item in seq --->
     ${item}
-<!--- endfor -->''')
-        assert tmpl.render(seq=list(range(5))) == '01234'
+<!--- endfor -->"""
+        )
+        assert tmpl.render(seq=list(range(5))) == "01234"
 
     def test_balancing(self, env):
-        tmpl = env.from_string('''{{{'foo':'bar'}.foo}}''')
-        assert tmpl.render() == 'bar'
+        tmpl = env.from_string("""{{{'foo':'bar'}.foo}}""")
+        assert tmpl.render() == "bar"
 
     def test_start_comment(self, env):
-        tmpl = env.from_string('''{# foo comment
+        tmpl = env.from_string(
+            """{# foo comment
 and bar comment #}
 {% macro blub() %}foo{% endmacro %}
-{{ blub() }}''')
-        assert tmpl.render().strip() == 'foo'
+{{ blub() }}"""
+        )
+        assert tmpl.render().strip() == "foo"
 
     def test_line_syntax(self, env):
-        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%')
-        tmpl = env.from_string('''\
+        env = Environment("<%", "%>", "${", "}", "<%#", "%>", "%")
+        tmpl = env.from_string(
+            """\
 <%# regular comment %>
 % for item in seq:
     ${item}
-% endfor''')
+% endfor"""
+        )
         assert [
             int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
         ] == list(range(5))
 
-        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##')
-        tmpl = env.from_string('''\
+        env = Environment("<%", "%>", "${", "}", "<%#", "%>", "%", "##")
+        tmpl = env.from_string(
+            """\
 <%# regular comment %>
 % for item in seq:
     ${item} ## the rest of the stuff
-% endfor''')
+% endfor"""
+        )
         assert [
             int(x.strip()) for x in tmpl.render(seq=list(range(5))).split()
         ] == list(range(5))
 
     def test_line_syntax_priority(self, env):
         # XXX: why is the whitespace there in front of the newline?
-        env = Environment('{%', '%}', '${', '}', '/*', '*/', '##', '#')
-        tmpl = env.from_string('''\
+        env = Environment("{%", "%}", "${", "}", "/*", "*/", "##", "#")
+        tmpl = env.from_string(
+            """\
 /* ignore me.
    I'm a multiline comment */
 ## for item in seq:
 * ${item}          # this is just extra stuff
-## endfor''')
-        assert tmpl.render(seq=[1, 2]).strip() == '* 1\n* 2'
-        env = Environment('{%', '%}', '${', '}', '/*', '*/', '#', '##')
-        tmpl = env.from_string('''\
+## endfor"""
+        )
+        assert tmpl.render(seq=[1, 2]).strip() == "* 1\n* 2"
+        env = Environment("{%", "%}", "${", "}", "/*", "*/", "#", "##")
+        tmpl = env.from_string(
+            """\
 /* ignore me.
    I'm a multiline comment */
 # for item in seq:
 * ${item}          ## this is just extra stuff
     ## extra stuff i just want to ignore
-# endfor''')
-        assert tmpl.render(seq=[1, 2]).strip() == '* 1\n\n* 2'
+# endfor"""
+        )
+        assert tmpl.render(seq=[1, 2]).strip() == "* 1\n\n* 2"
 
     def test_error_messages(self, env):
         def assert_error(code, expected):
             with pytest.raises(TemplateSyntaxError, match=expected):
                 Template(code)
 
-        assert_error('{% for item in seq %}...{% endif %}',
-                     "Encountered unknown tag 'endif'. Jinja was looking "
-                     "for the following tags: 'endfor' or 'else'. The "
-                     "innermost block that needs to be closed is 'for'.")
         assert_error(
-            '{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}',
+            "{% for item in seq %}...{% endif %}",
+            "Encountered unknown tag 'endif'. Jinja was looking "
+            "for the following tags: 'endfor' or 'else'. The "
+            "innermost block that needs to be closed is 'for'.",
+        )
+        assert_error(
+            "{% if foo %}{% for item in seq %}...{% endfor %}{% endfor %}",
             "Encountered unknown tag 'endfor'. Jinja was looking for "
             "the following tags: 'elif' or 'else' or 'endif'. The "
-            "innermost block that needs to be closed is 'if'.")
-        assert_error('{% if foo %}',
-                     "Unexpected end of template. Jinja was looking for the "
-                     "following tags: 'elif' or 'else' or 'endif'. The "
-                     "innermost block that needs to be closed is 'if'.")
-        assert_error('{% for item in seq %}',
-                     "Unexpected end of template. Jinja was looking for the "
-                     "following tags: 'endfor' or 'else'. The innermost block "
-                     "that needs to be closed is 'for'.")
+            "innermost block that needs to be closed is 'if'.",
+        )
+        assert_error(
+            "{% if foo %}",
+            "Unexpected end of template. Jinja was looking for the "
+            "following tags: 'elif' or 'else' or 'endif'. The "
+            "innermost block that needs to be closed is 'if'.",
+        )
         assert_error(
-            '{% block foo-bar-baz %}',
+            "{% for item in seq %}",
+            "Unexpected end of template. Jinja was looking for the "
+            "following tags: 'endfor' or 'else'. The innermost block "
+            "that needs to be closed is 'for'.",
+        )
+        assert_error(
+            "{% block foo-bar-baz %}",
             "Block names in Jinja have to be valid Python identifiers "
-            "and may not contain hyphens, use an underscore instead.")
-        assert_error('{% unknown_tag %}',
-                     "Encountered unknown tag 'unknown_tag'.")
+            "and may not contain hyphens, use an underscore instead.",
+        )
+        assert_error("{% unknown_tag %}", "Encountered unknown tag 'unknown_tag'.")
 
 
 @pytest.mark.lexnparse
 @pytest.mark.syntax
 class TestSyntax(object):
-
     def test_call(self, env):
         env = Environment()
-        env.globals['foo'] = lambda a, b, c, e, g: a + b + c + e + g
-        tmpl = env.from_string(
-            "{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}"
-        )
-        assert tmpl.render() == 'abdfh'
+        env.globals["foo"] = lambda a, b, c, e, g: a + b + c + e + g
+        tmpl = env.from_string("{{ foo('a', c='d', e='f', *['b'], **{'g': 'h'}) }}")
+        assert tmpl.render() == "abdfh"
 
     def test_slicing(self, env):
-        tmpl = env.from_string('{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}')
-        assert tmpl.render() == '[1, 2, 3]|[3, 2, 1]'
+        tmpl = env.from_string("{{ [1, 2, 3][:] }}|{{ [1, 2, 3][::-1] }}")
+        assert tmpl.render() == "[1, 2, 3]|[3, 2, 1]"
 
     def test_attr(self, env):
         tmpl = env.from_string("{{ foo.bar }}|{{ foo['bar'] }}")
-        assert tmpl.render(foo={'bar': 42}) == '42|42'
+        assert tmpl.render(foo={"bar": 42}) == "42|42"
 
     def test_subscript(self, env):
         tmpl = env.from_string("{{ foo[0] }}|{{ foo[-1] }}")
-        assert tmpl.render(foo=[0, 1, 2]) == '0|2'
+        assert tmpl.render(foo=[0, 1, 2]) == "0|2"
 
     def test_tuple(self, env):
-        tmpl = env.from_string('{{ () }}|{{ (1,) }}|{{ (1, 2) }}')
-        assert tmpl.render() == '()|(1,)|(1, 2)'
+        tmpl = env.from_string("{{ () }}|{{ (1,) }}|{{ (1, 2) }}")
+        assert tmpl.render() == "()|(1,)|(1, 2)"
 
     def test_math(self, env):
-        tmpl = env.from_string('{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}')
-        assert tmpl.render() == '1.5|8'
+        tmpl = env.from_string("{{ (1 + 1 * 2) - 3 / 2 }}|{{ 2**3 }}")
+        assert tmpl.render() == "1.5|8"
 
     def test_div(self, env):
-        tmpl = env.from_string('{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}')
-        assert tmpl.render() == '1|1.5|1'
+        tmpl = env.from_string("{{ 3 // 2 }}|{{ 3 / 2 }}|{{ 3 % 2 }}")
+        assert tmpl.render() == "1|1.5|1"
 
     def test_unary(self, env):
-        tmpl = env.from_string('{{ +3 }}|{{ -3 }}')
-        assert tmpl.render() == '3|-3'
+        tmpl = env.from_string("{{ +3 }}|{{ -3 }}")
+        assert tmpl.render() == "3|-3"
 
     def test_concat(self, env):
         tmpl = env.from_string("{{ [1, 2] ~ 'foo' }}")
-        assert tmpl.render() == '[1, 2]foo'
+        assert tmpl.render() == "[1, 2]foo"
 
     @pytest.mark.parametrize(
         ("a", "op", "b"),
@@ -366,8 +401,8 @@ class TestSyntax(object):
         assert t.render(a=4, b=2, c=3) == expect
 
     def test_inop(self, env):
-        tmpl = env.from_string('{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}')
-        assert tmpl.render() == 'True|False'
+        tmpl = env.from_string("{{ 1 in [1, 2, 3] }}|{{ 1 not in [1, 2, 3] }}")
+        assert tmpl.render() == "True|False"
 
     @pytest.mark.parametrize("value", ("[]", "{}", "()"))
     def test_collection_literal(self, env, value):
@@ -389,332 +424,414 @@ class TestSyntax(object):
             ("2.5e+100", "2.5e+100"),
             ("25.6e-10", "2.56e-09"),
             ("1_2.3_4e5_6", "1.234e+57"),
-        )
+        ),
     )
     def test_numeric_literal(self, env, value, expect):
         t = env.from_string("{{ %s }}" % value)
         assert t.render() == expect
 
     def test_bool(self, env):
-        tmpl = env.from_string('{{ true and false }}|{{ false '
-                               'or true }}|{{ not false }}')
-        assert tmpl.render() == 'False|True|True'
+        tmpl = env.from_string(
+            "{{ true and false }}|{{ false or true }}|{{ not false }}"
+        )
+        assert tmpl.render() == "False|True|True"
 
     def test_grouping(self, env):
         tmpl = env.from_string(
-            '{{ (true and false) or (false and true) and not false }}')
-        assert tmpl.render() == 'False'
+            "{{ (true and false) or (false and true) and not false }}"
+        )
+        assert tmpl.render() == "False"
 
     def test_django_attr(self, env):
-        tmpl = env.from_string('{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}')
-        assert tmpl.render() == '1|1'
+        tmpl = env.from_string("{{ [1, 2, 3].0 }}|{{ [[1]].0.0 }}")
+        assert tmpl.render() == "1|1"
 
     def test_conditional_expression(self, env):
-        tmpl = env.from_string('''{{ 0 if true else 1 }}''')
-        assert tmpl.render() == '0'
+        tmpl = env.from_string("""{{ 0 if true else 1 }}""")
+        assert tmpl.render() == "0"
 
     def test_short_conditional_expression(self, env):
-        tmpl = env.from_string('<{{ 1 if false }}>')
-        assert tmpl.render() == '<>'
+        tmpl = env.from_string("<{{ 1 if false }}>")
+        assert tmpl.render() == "<>"
 
-        tmpl = env.from_string('<{{ (1 if false).bar }}>')
+        tmpl = env.from_string("<{{ (1 if false).bar }}>")
         pytest.raises(UndefinedError, tmpl.render)
 
     def test_filter_priority(self, env):
         tmpl = env.from_string('{{ "foo"|upper + "bar"|upper }}')
-        assert tmpl.render() == 'FOOBAR'
+        assert tmpl.render() == "FOOBAR"
 
     def test_function_calls(self, env):
         tests = [
-            (True, '*foo, bar'),
-            (True, '*foo, *bar'),
-            (True, '**foo, *bar'),
-            (True, '**foo, bar'),
-            (True, '**foo, **bar'),
-            (True, '**foo, bar=42'),
-            (False, 'foo, bar'),
-            (False, 'foo, bar=42'),
-            (False, 'foo, bar=23, *args'),
-            (False, 'foo, *args, bar=23'),
-            (False, 'a, b=c, *d, **e'),
-            (False, '*foo, bar=42'),
-            (False, '*foo, **bar'),
-            (False, '*foo, bar=42, **baz'),
-            (False, 'foo, *args, bar=23, **baz'),
+            (True, "*foo, bar"),
+            (True, "*foo, *bar"),
+            (True, "**foo, *bar"),
+            (True, "**foo, bar"),
+            (True, "**foo, **bar"),
+            (True, "**foo, bar=42"),
+            (False, "foo, bar"),
+            (False, "foo, bar=42"),
+            (False, "foo, bar=23, *args"),
+            (False, "foo, *args, bar=23"),
+            (False, "a, b=c, *d, **e"),
+            (False, "*foo, bar=42"),
+            (False, "*foo, **bar"),
+            (False, "*foo, bar=42, **baz"),
+            (False, "foo, *args, bar=23, **baz"),
         ]
         for should_fail, sig in tests:
             if should_fail:
-                pytest.raises(TemplateSyntaxError,
-                              env.from_string, '{{ foo(%s) }}' % sig)
+                pytest.raises(
+                    TemplateSyntaxError, env.from_string, "{{ foo(%s) }}" % sig
+                )
             else:
-                env.from_string('foo(%s)' % sig)
+                env.from_string("foo(%s)" % sig)
 
     def test_tuple_expr(self, env):
         for tmpl in [
-            '{{ () }}',
-            '{{ (1, 2) }}',
-            '{{ (1, 2,) }}',
-            '{{ 1, }}',
-            '{{ 1, 2 }}',
-            '{% for foo, bar in seq %}...{% endfor %}',
-            '{% for x in foo, bar %}...{% endfor %}',
-            '{% for x in foo, %}...{% endfor %}'
+            "{{ () }}",
+            "{{ (1, 2) }}",
+            "{{ (1, 2,) }}",
+            "{{ 1, }}",
+            "{{ 1, 2 }}",
+            "{% for foo, bar in seq %}...{% endfor %}",
+            "{% for x in foo, bar %}...{% endfor %}",
+            "{% for x in foo, %}...{% endfor %}",
         ]:
             assert env.from_string(tmpl)
 
     def test_trailing_comma(self, env):
-        tmpl = env.from_string('{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}')
-        assert tmpl.render().lower() == '(1, 2)|[1, 2]|{1: 2}'
+        tmpl = env.from_string("{{ (1, 2,) }}|{{ [1, 2,] }}|{{ {1: 2,} }}")
+        assert tmpl.render().lower() == "(1, 2)|[1, 2]|{1: 2}"
 
     def test_block_end_name(self, env):
-        env.from_string('{% block foo %}...{% endblock foo %}')
-        pytest.raises(TemplateSyntaxError, env.from_string,
-                      '{% block x %}{% endblock y %}')
+        env.from_string("{% block foo %}...{% endblock foo %}")
+        pytest.raises(
+            TemplateSyntaxError, env.from_string, "{% block x %}{% endblock y %}"
+        )
 
     def test_constant_casing(self, env):
         for const in True, False, None:
-            tmpl = env.from_string('{{ %s }}|{{ %s }}|{{ %s }}' % (
-                str(const), str(const).lower(), str(const).upper()
-            ))
-            assert tmpl.render() == '%s|%s|' % (const, const)
+            tmpl = env.from_string(
+                "{{ %s }}|{{ %s }}|{{ %s }}"
+                % (str(const), str(const).lower(), str(const).upper())
+            )
+            assert tmpl.render() == "%s|%s|" % (const, const)
 
     def test_test_chaining(self, env):
-        pytest.raises(TemplateSyntaxError, env.from_string,
-                      '{{ foo is string is sequence }}')
-        assert env.from_string(
-            '{{ 42 is string or 42 is number }}'
-        ).render() == 'True'
+        pytest.raises(
+            TemplateSyntaxError, env.from_string, "{{ foo is string is sequence }}"
+        )
+        assert env.from_string("{{ 42 is string or 42 is number }}").render() == "True"
 
     def test_string_concatenation(self, env):
         tmpl = env.from_string('{{ "foo" "bar" "baz" }}')
-        assert tmpl.render() == 'foobarbaz'
+        assert tmpl.render() == "foobarbaz"
 
     def test_notin(self, env):
         bar = range(100)
-        tmpl = env.from_string('''{{ not 42 in bar }}''')
+        tmpl = env.from_string("""{{ not 42 in bar }}""")
         assert tmpl.render(bar=bar) == text_type(not 42 in bar)
 
     def test_operator_precedence(self, env):
-        tmpl = env.from_string('''{{ 2 * 3 + 4 % 2 + 1 - 2 }}''')
+        tmpl = env.from_string("""{{ 2 * 3 + 4 % 2 + 1 - 2 }}""")
         assert tmpl.render() == text_type(2 * 3 + 4 % 2 + 1 - 2)
 
     def test_implicit_subscribed_tuple(self, env):
         class Foo(object):
             def __getitem__(self, x):
                 return x
-        t = env.from_string('{{ foo[1, 2] }}')
-        assert t.render(foo=Foo()) == u'(1, 2)'
+
+        t = env.from_string("{{ foo[1, 2] }}")
+        assert t.render(foo=Foo()) == u"(1, 2)"
 
     def test_raw2(self, env):
-        tmpl = env.from_string('{% raw %}{{ FOO }} and {% BAR %}{% endraw %}')
-        assert tmpl.render() == '{{ FOO }} and {% BAR %}'
+        tmpl = env.from_string("{% raw %}{{ FOO }} and {% BAR %}{% endraw %}")
+        assert tmpl.render() == "{{ FOO }} and {% BAR %}"
 
     def test_const(self, env):
         tmpl = env.from_string(
-            '{{ true }}|{{ false }}|{{ none }}|'
-            '{{ none is defined }}|{{ missing is defined }}')
-        assert tmpl.render() == 'True|False|None|True|False'
+            "{{ true }}|{{ false }}|{{ none }}|"
+            "{{ none is defined }}|{{ missing is defined }}"
+        )
+        assert tmpl.render() == "True|False|None|True|False"
 
     def test_neg_filter_priority(self, env):
-        node = env.parse('{{ -1|foo }}')
+        node = env.parse("{{ -1|foo }}")
         assert isinstance(node.body[0].nodes[0], nodes.Filter)
         assert isinstance(node.body[0].nodes[0].node, nodes.Neg)
 
     def test_const_assign(self, env):
-        constass1 = '''{% set true = 42 %}'''
-        constass2 = '''{% for none in seq %}{% endfor %}'''
+        constass1 = """{% set true = 42 %}"""
+        constass2 = """{% for none in seq %}{% endfor %}"""
         for tmpl in constass1, constass2:
             pytest.raises(TemplateSyntaxError, env.from_string, tmpl)
 
     def test_localset(self, env):
-        tmpl = env.from_string('''{% set foo = 0 %}\
+        tmpl = env.from_string(
+            """{% set foo = 0 %}\
 {% for item in [1, 2] %}{% set foo = 1 %}{% endfor %}\
-{{ foo }}''')
-        assert tmpl.render() == '0'
+{{ foo }}"""
+        )
+        assert tmpl.render() == "0"
 
     def test_parse_unary(self, env):
         tmpl = env.from_string('{{ -foo["bar"] }}')
-        assert tmpl.render(foo={'bar': 42}) == '-42'
+        assert tmpl.render(foo={"bar": 42}) == "-42"
         tmpl = env.from_string('{{ -foo["bar"]|abs }}')
-        assert tmpl.render(foo={'bar': 42}) == '42'
+        assert tmpl.render(foo={"bar": 42}) == "42"
 
 
 @pytest.mark.lexnparse
 @pytest.mark.lstripblocks
 class TestLstripBlocks(object):
-
     def test_lstrip(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''    {% if True %}\n    {% endif %}''')
+        tmpl = env.from_string("""    {% if True %}\n    {% endif %}""")
         assert tmpl.render() == "\n"
 
     def test_lstrip_trim(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''    {% if True %}\n    {% endif %}''')
+        tmpl = env.from_string("""    {% if True %}\n    {% endif %}""")
         assert tmpl.render() == ""
 
     def test_no_lstrip(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''    {%+ if True %}\n    {%+ endif %}''')
+        tmpl = env.from_string("""    {%+ if True %}\n    {%+ endif %}""")
         assert tmpl.render() == "    \n    "
 
     def test_lstrip_blocks_false_with_no_lstrip(self, env):
         # Test that + is a NOP (but does not cause an error) if lstrip_blocks=False
         env = Environment(lstrip_blocks=False, trim_blocks=False)
-        tmpl = env.from_string('''    {% if True %}\n    {% endif %}''')
+        tmpl = env.from_string("""    {% if True %}\n    {% endif %}""")
         assert tmpl.render() == "    \n    "
-        tmpl = env.from_string('''    {%+ if True %}\n    {%+ endif %}''')
+        tmpl = env.from_string("""    {%+ if True %}\n    {%+ endif %}""")
         assert tmpl.render() == "    \n    "
 
     def test_lstrip_endline(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string(
-            '''    hello{% if True %}\n    goodbye{% endif %}''')
+        tmpl = env.from_string("""    hello{% if True %}\n    goodbye{% endif %}""")
         assert tmpl.render() == "    hello\n    goodbye"
 
     def test_lstrip_inline(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''    {% if True %}hello    {% endif %}''')
-        assert tmpl.render() == 'hello    '
+        tmpl = env.from_string("""    {% if True %}hello    {% endif %}""")
+        assert tmpl.render() == "hello    "
 
     def test_lstrip_nested(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
         tmpl = env.from_string(
-            '''    {% if True %}a {% if True %}b {% endif %}c {% endif %}''')
-        assert tmpl.render() == 'a b c '
+            """    {% if True %}a {% if True %}b {% endif %}c {% endif %}"""
+        )
+        assert tmpl.render() == "a b c "
 
     def test_lstrip_left_chars(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''    abc {% if True %}
-        hello{% endif %}''')
-        assert tmpl.render() == '    abc \n        hello'
+        tmpl = env.from_string(
+            """    abc {% if True %}
+        hello{% endif %}"""
+        )
+        assert tmpl.render() == "    abc \n        hello"
 
     def test_lstrip_embeded_strings(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''    {% set x = " {% str %} " %}{{ x }}''')
-        assert tmpl.render() == ' {% str %} '
+        tmpl = env.from_string("""    {% set x = " {% str %} " %}{{ x }}""")
+        assert tmpl.render() == " {% str %} "
 
     def test_lstrip_preserve_leading_newlines(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''\n\n\n{% set hello = 1 %}''')
-        assert tmpl.render() == '\n\n\n'
+        tmpl = env.from_string("""\n\n\n{% set hello = 1 %}""")
+        assert tmpl.render() == "\n\n\n"
 
     def test_lstrip_comment(self, env):
         env = Environment(lstrip_blocks=True, trim_blocks=False)
-        tmpl = env.from_string('''    {# if True #}
+        tmpl = env.from_string(
+            """    {# if True #}
 hello
-    {#endif#}''')
-        assert tmpl.render() == '\nhello\n'
+    {#endif#}"""
+        )
+        assert tmpl.render() == "\nhello\n"
 
     def test_lstrip_angle_bracket_simple(self, env):
-        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''    <% if True %>hello    <% endif %>''')
-        assert tmpl.render() == 'hello    '
+        env = Environment(
+            "<%",
+            "%>",
+            "${",
+            "}",
+            "<%#",
+            "%>",
+            "%",
+            "##",
+            lstrip_blocks=True,
+            trim_blocks=True,
+        )
+        tmpl = env.from_string("""    <% if True %>hello    <% endif %>""")
+        assert tmpl.render() == "hello    "
 
     def test_lstrip_angle_bracket_comment(self, env):
-        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''    <%# if True %>hello    <%# endif %>''')
-        assert tmpl.render() == 'hello    '
+        env = Environment(
+            "<%",
+            "%>",
+            "${",
+            "}",
+            "<%#",
+            "%>",
+            "%",
+            "##",
+            lstrip_blocks=True,
+            trim_blocks=True,
+        )
+        tmpl = env.from_string("""    <%# if True %>hello    <%# endif %>""")
+        assert tmpl.render() == "hello    "
 
     def test_lstrip_angle_bracket(self, env):
-        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<%",
+            "%>",
+            "${",
+            "}",
+            "<%#",
+            "%>",
+            "%",
+            "##",
+            lstrip_blocks=True,
+            trim_blocks=True,
+        )
+        tmpl = env.from_string(
+            """\
     <%# regular comment %>
     <% for item in seq %>
 ${item} ## the rest of the stuff
-   <% endfor %>''')
-        assert tmpl.render(seq=range(5)) == \
-            ''.join('%s\n' % x for x in range(5))
+   <% endfor %>"""
+        )
+        assert tmpl.render(seq=range(5)) == "".join("%s\n" % x for x in range(5))
 
     def test_lstrip_angle_bracket_compact(self, env):
-        env = Environment('<%', '%>', '${', '}', '<%#', '%>', '%', '##',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<%",
+            "%>",
+            "${",
+            "}",
+            "<%#",
+            "%>",
+            "%",
+            "##",
+            lstrip_blocks=True,
+            trim_blocks=True,
+        )
+        tmpl = env.from_string(
+            """\
     <%#regular comment%>
     <%for item in seq%>
 ${item} ## the rest of the stuff
-   <%endfor%>''')
-        assert tmpl.render(seq=range(5)) == \
-            ''.join('%s\n' % x for x in range(5))
+   <%endfor%>"""
+        )
+        assert tmpl.render(seq=range(5)) == "".join("%s\n" % x for x in range(5))
 
     def test_php_syntax_with_manual(self, env):
-        env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
+        )
+        tmpl = env.from_string(
+            """\
     <!-- I'm a comment, I'm not interesting -->
     <? for item in seq -?>
         <?= item ?>
-    <?- endfor ?>''')
-        assert tmpl.render(seq=range(5)) == '01234'
+    <?- endfor ?>"""
+        )
+        assert tmpl.render(seq=range(5)) == "01234"
 
     def test_php_syntax(self, env):
-        env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
+        )
+        tmpl = env.from_string(
+            """\
     <!-- I'm a comment, I'm not interesting -->
     <? for item in seq ?>
         <?= item ?>
-    <? endfor ?>''')
-        assert tmpl.render(seq=range(5)) \
-            == ''.join('        %s\n' % x for x in range(5))
+    <? endfor ?>"""
+        )
+        assert tmpl.render(seq=range(5)) == "".join(
+            "        %s\n" % x for x in range(5)
+        )
 
     def test_php_syntax_compact(self, env):
-        env = Environment('<?', '?>', '<?=', '?>', '<!--', '-->',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True
+        )
+        tmpl = env.from_string(
+            """\
     <!-- I'm a comment, I'm not interesting -->
     <?for item in seq?>
         <?=item?>
-    <?endfor?>''')
-        assert tmpl.render(seq=range(5)) \
-            == ''.join('        %s\n' % x for x in range(5))
+    <?endfor?>"""
+        )
+        assert tmpl.render(seq=range(5)) == "".join(
+            "        %s\n" % x for x in range(5)
+        )
 
     def test_erb_syntax(self, env):
-        env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>',
-                          lstrip_blocks=True, trim_blocks=True)
+        env = Environment(
+            "<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
+        )
         # env.from_string('')
         # for n,r in env.lexer.rules.iteritems():
         #    print n
         # print env.lexer.rules['root'][0][0].pattern
         # print "'%s'" % tmpl.render(seq=range(5))
-        tmpl = env.from_string('''\
+        tmpl = env.from_string(
+            """\
 <%# I'm a comment, I'm not interesting %>
     <% for item in seq %>
     <%= item %>
     <% endfor %>
-''')
-        assert tmpl.render(seq=range(5)) \
-            == ''.join('    %s\n' % x for x in range(5))
+"""
+        )
+        assert tmpl.render(seq=range(5)) == "".join("    %s\n" % x for x in range(5))
 
     def test_erb_syntax_with_manual(self, env):
-        env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
+        )
+        tmpl = env.from_string(
+            """\
 <%# I'm a comment, I'm not interesting %>
     <% for item in seq -%>
         <%= item %>
-    <%- endfor %>''')
-        assert tmpl.render(seq=range(5)) == '01234'
+    <%- endfor %>"""
+        )
+        assert tmpl.render(seq=range(5)) == "01234"
 
     def test_erb_syntax_no_lstrip(self, env):
-        env = Environment('<%', '%>', '<%=', '%>', '<%#', '%>',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<%", "%>", "<%=", "%>", "<%#", "%>", lstrip_blocks=True, trim_blocks=True
+        )
+        tmpl = env.from_string(
+            """\
 <%# I'm a comment, I'm not interesting %>
     <%+ for item in seq -%>
         <%= item %>
-    <%- endfor %>''')
-        assert tmpl.render(seq=range(5)) == '    01234'
+    <%- endfor %>"""
+        )
+        assert tmpl.render(seq=range(5)) == "    01234"
 
     def test_comment_syntax(self, env):
-        env = Environment('<!--', '-->', '${', '}', '<!--#', '-->',
-                          lstrip_blocks=True, trim_blocks=True)
-        tmpl = env.from_string('''\
+        env = Environment(
+            "<!--",
+            "-->",
+            "${",
+            "}",
+            "<!--#",
+            "-->",
+            lstrip_blocks=True,
+            trim_blocks=True,
+        )
+        tmpl = env.from_string(
+            """\
 <!--# I'm a comment, I'm not interesting -->\
 <!-- for item in seq --->
     ${item}
-<!--- endfor -->''')
-        assert tmpl.render(seq=range(5)) == '01234'
+<!--- endfor -->"""
+        )
+        assert tmpl.render(seq=range(5)) == "01234"
index 68c138425b7c6158bd4060672ae71b0bbe5110ec..44000e19d8a0b749b7d11a28cb889189d01bfc3a 100644 (file)
@@ -30,15 +30,15 @@ from jinja2.loaders import split_template_path
 class TestLoaders(object):
     def test_dict_loader(self, dict_loader):
         env = Environment(loader=dict_loader)
-        tmpl = env.get_template('justdict.html')
-        assert tmpl.render().strip() == 'FOO'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
+        tmpl = env.get_template("justdict.html")
+        assert tmpl.render().strip() == "FOO"
+        pytest.raises(TemplateNotFound, env.get_template, "missing.html")
 
     def test_package_loader(self, package_loader):
         env = Environment(loader=package_loader)
-        tmpl = env.get_template('test.html')
-        assert tmpl.render().strip() == 'BAR'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
+        tmpl = env.get_template("test.html")
+        assert tmpl.render().strip() == "BAR"
+        pytest.raises(TemplateNotFound, env.get_template, "missing.html")
 
     def test_filesystem_loader_overlapping_names(self, filesystem_loader):
         res = os.path.dirname(filesystem_loader.searchpath[0])
@@ -52,91 +52,94 @@ class TestLoaders(object):
 
     def test_choice_loader(self, choice_loader):
         env = Environment(loader=choice_loader)
-        tmpl = env.get_template('justdict.html')
-        assert tmpl.render().strip() == 'FOO'
-        tmpl = env.get_template('test.html')
-        assert tmpl.render().strip() == 'BAR'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
+        tmpl = env.get_template("justdict.html")
+        assert tmpl.render().strip() == "FOO"
+        tmpl = env.get_template("test.html")
+        assert tmpl.render().strip() == "BAR"
+        pytest.raises(TemplateNotFound, env.get_template, "missing.html")
 
     def test_function_loader(self, function_loader):
         env = Environment(loader=function_loader)
-        tmpl = env.get_template('justfunction.html')
-        assert tmpl.render().strip() == 'FOO'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
+        tmpl = env.get_template("justfunction.html")
+        assert tmpl.render().strip() == "FOO"
+        pytest.raises(TemplateNotFound, env.get_template, "missing.html")
 
     def test_prefix_loader(self, prefix_loader):
         env = Environment(loader=prefix_loader)
-        tmpl = env.get_template('a/test.html')
-        assert tmpl.render().strip() == 'BAR'
-        tmpl = env.get_template('b/justdict.html')
-        assert tmpl.render().strip() == 'FOO'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing')
+        tmpl = env.get_template("a/test.html")
+        assert tmpl.render().strip() == "BAR"
+        tmpl = env.get_template("b/justdict.html")
+        assert tmpl.render().strip() == "FOO"
+        pytest.raises(TemplateNotFound, env.get_template, "missing")
 
     def test_caching(self):
         changed = False
 
         class TestLoader(loaders.BaseLoader):
             def get_source(self, environment, template):
-                return u'foo', None, lambda: not changed
+                return u"foo", None, lambda: not changed
+
         env = Environment(loader=TestLoader(), cache_size=-1)
-        tmpl = env.get_template('template')
-        assert tmpl is env.get_template('template')
+        tmpl = env.get_template("template")
+        assert tmpl is env.get_template("template")
         changed = True
-        assert tmpl is not env.get_template('template')
+        assert tmpl is not env.get_template("template")
         changed = False
 
     def test_no_cache(self):
-        mapping = {'foo': 'one'}
+        mapping = {"foo": "one"}
         env = Environment(loader=loaders.DictLoader(mapping), cache_size=0)
-        assert env.get_template('foo') is not env.get_template('foo')
+        assert env.get_template("foo") is not env.get_template("foo")
 
     def test_limited_size_cache(self):
-        mapping = {'one': 'foo', 'two': 'bar', 'three': 'baz'}
+        mapping = {"one": "foo", "two": "bar", "three": "baz"}
         loader = loaders.DictLoader(mapping)
         env = Environment(loader=loader, cache_size=2)
-        t1 = env.get_template('one')
-        t2 = env.get_template('two')
-        assert t2 is env.get_template('two')
-        assert t1 is env.get_template('one')
-        t3 = env.get_template('three')
+        t1 = env.get_template("one")
+        t2 = env.get_template("two")
+        assert t2 is env.get_template("two")
+        assert t1 is env.get_template("one")
+        t3 = env.get_template("three")
         loader_ref = weakref.ref(loader)
-        assert (loader_ref, 'one') in env.cache
-        assert (loader_ref, 'two') not in env.cache
-        assert (loader_ref, 'three') in env.cache
+        assert (loader_ref, "one") in env.cache
+        assert (loader_ref, "two") not in env.cache
+        assert (loader_ref, "three") in env.cache
 
     def test_cache_loader_change(self):
-        loader1 = loaders.DictLoader({'foo': 'one'})
-        loader2 = loaders.DictLoader({'foo': 'two'})
+        loader1 = loaders.DictLoader({"foo": "one"})
+        loader2 = loaders.DictLoader({"foo": "two"})
         env = Environment(loader=loader1, cache_size=2)
-        assert env.get_template('foo').render() == 'one'
+        assert env.get_template("foo").render() == "one"
         env.loader = loader2
-        assert env.get_template('foo').render() == 'two'
+        assert env.get_template("foo").render() == "two"
 
     def test_dict_loader_cache_invalidates(self):
-        mapping = {'foo': "one"}
+        mapping = {"foo": "one"}
         env = Environment(loader=loaders.DictLoader(mapping))
-        assert env.get_template('foo').render() == "one"
-        mapping['foo'] = "two"
-        assert env.get_template('foo').render() == "two"
+        assert env.get_template("foo").render() == "one"
+        mapping["foo"] = "two"
+        assert env.get_template("foo").render() == "two"
 
     def test_split_template_path(self):
-        assert split_template_path('foo/bar') == ['foo', 'bar']
-        assert split_template_path('./foo/bar') == ['foo', 'bar']
-        pytest.raises(TemplateNotFound, split_template_path, '../foo')
+        assert split_template_path("foo/bar") == ["foo", "bar"]
+        assert split_template_path("./foo/bar") == ["foo", "bar"]
+        pytest.raises(TemplateNotFound, split_template_path, "../foo")
 
 
 @pytest.mark.loaders
 @pytest.mark.filesystemloader
 class TestFileSystemLoader(object):
-    searchpath = os.path.dirname(os.path.abspath(__file__)) + '/res/templates'
+    searchpath = os.path.join(
+        os.path.dirname(os.path.abspath(__file__)), "res", "templates"
+    )
 
     @staticmethod
     def _test_common(env):
-        tmpl = env.get_template('test.html')
-        assert tmpl.render().strip() == 'BAR'
-        tmpl = env.get_template('foo/test.html')
-        assert tmpl.render().strip() == 'FOO'
-        pytest.raises(TemplateNotFound, env.get_template, 'missing.html')
+        tmpl = env.get_template("test.html")
+        assert tmpl.render().strip() == "BAR"
+        tmpl = env.get_template("foo/test.html")
+        assert tmpl.render().strip() == "FOO"
+        pytest.raises(TemplateNotFound, env.get_template, "missing.html")
 
     def test_searchpath_as_str(self):
         filesystem_loader = loaders.FileSystemLoader(self.searchpath)
@@ -144,9 +147,10 @@ class TestFileSystemLoader(object):
         env = Environment(loader=filesystem_loader)
         self._test_common(env)
 
-    @pytest.mark.skipif(PY2, reason='pathlib is not available in Python 2')
+    @pytest.mark.skipif(PY2, reason="pathlib is not available in Python 2")
     def test_searchpath_as_pathlib(self):
         import pathlib
+
         searchpath = pathlib.Path(self.searchpath)
 
         filesystem_loader = loaders.FileSystemLoader(searchpath)
@@ -154,12 +158,13 @@ class TestFileSystemLoader(object):
         env = Environment(loader=filesystem_loader)
         self._test_common(env)
 
-    @pytest.mark.skipif(PY2, reason='pathlib is not available in Python 2')
+    @pytest.mark.skipif(PY2, reason="pathlib is not available in Python 2")
     def test_searchpath_as_list_including_pathlib(self):
         import pathlib
+
         searchpath = pathlib.Path(self.searchpath)
 
-        filesystem_loader = loaders.FileSystemLoader(['/tmp/templates', searchpath])
+        filesystem_loader = loaders.FileSystemLoader(["/tmp/templates", searchpath])
 
         env = Environment(loader=filesystem_loader)
         self._test_common(env)
@@ -168,26 +173,23 @@ class TestFileSystemLoader(object):
         filesystem_loader = loaders.FileSystemLoader(self.searchpath)
 
         env = Environment(loader=filesystem_loader)
-        tmpl1 = env.get_template('test.html')
-        tmpl2 = env.get_template('test.html')
+        tmpl1 = env.get_template("test.html")
+        tmpl2 = env.get_template("test.html")
         assert tmpl1 is tmpl2
 
-        os.utime(
-            os.path.join(self.searchpath, "test.html"),
-            (time.time(), time.time())
-        )
-        tmpl3 = env.get_template('test.html')
+        os.utime(os.path.join(self.searchpath, "test.html"), (time.time(), time.time()))
+        tmpl3 = env.get_template("test.html")
         assert tmpl1 is not tmpl3
 
-    @pytest.mark.parametrize('encoding, expected_text', [
-        ('utf-8', u'tech'),
-        ('utf-16', u'整档'),
-    ])
-    def test_uses_specified_encoding(self, encoding, expected_text):
-        filesystem_loader = loaders.FileSystemLoader(self.searchpath, encoding=encoding)
-        env = Environment(loader=filesystem_loader)
-        tmpl = env.get_template('variable_encoding.txt')
-        assert tmpl.render().strip() == expected_text
+    @pytest.mark.parametrize(
+        ("encoding", "expect"),
+        [("utf-8", u"文字化け"), ("iso-8859-1", u"æ\x96\x87å\xad\x97å\x8c\x96ã\x81\x91"),],
+    )
+    def test_uses_specified_encoding(self, encoding, expect):
+        loader = loaders.FileSystemLoader(self.searchpath, encoding=encoding)
+        e = Environment(loader=loader)
+        t = e.get_template("mojibake.txt")
+        assert t.render() == expect
 
 
 @pytest.mark.loaders
@@ -195,22 +197,22 @@ class TestFileSystemLoader(object):
 class TestModuleLoader(object):
     archive = None
 
-    def compile_down(self, prefix_loader, zip='deflated', py_compile=False):
+    def compile_down(self, prefix_loader, zip="deflated", py_compile=False):
         log = []
         self.reg_env = Environment(loader=prefix_loader)
         if zip is not None:
-            fd, self.archive = tempfile.mkstemp(suffix='.zip')
+            fd, self.archive = tempfile.mkstemp(suffix=".zip")
             os.close(fd)
         else:
             self.archive = tempfile.mkdtemp()
-        self.reg_env.compile_templates(self.archive, zip=zip,
-                                       log_function=log.append,
-                                       py_compile=py_compile)
+        self.reg_env.compile_templates(
+            self.archive, zip=zip, log_function=log.append, py_compile=py_compile
+        )
         self.mod_env = Environment(loader=loaders.ModuleLoader(self.archive))
-        return ''.join(log)
+        return "".join(log)
 
     def teardown(self):
-        if hasattr(self, 'mod_env'):
+        if hasattr(self, "mod_env"):
             if os.path.isfile(self.archive):
                 os.remove(self.archive)
             else:
@@ -219,27 +221,31 @@ class TestModuleLoader(object):
 
     def test_log(self, prefix_loader):
         log = self.compile_down(prefix_loader)
-        assert 'Compiled "a/foo/test.html" as ' \
-               'tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a' in log
-        assert 'Finished compiling templates' in log
-        assert 'Could not compile "a/syntaxerror.html": ' \
-               'Encountered unknown tag \'endif\'' in log
+        assert (
+            'Compiled "a/foo/test.html" as '
+            "tmpl_a790caf9d669e39ea4d280d597ec891c4ef0404a" in log
+        )
+        assert "Finished compiling templates" in log
+        assert (
+            'Could not compile "a/syntaxerror.html": '
+            "Encountered unknown tag 'endif'" in log
+        )
 
     def _test_common(self):
-        tmpl1 = self.reg_env.get_template('a/test.html')
-        tmpl2 = self.mod_env.get_template('a/test.html')
+        tmpl1 = self.reg_env.get_template("a/test.html")
+        tmpl2 = self.mod_env.get_template("a/test.html")
         assert tmpl1.render() == tmpl2.render()
 
-        tmpl1 = self.reg_env.get_template('b/justdict.html')
-        tmpl2 = self.mod_env.get_template('b/justdict.html')
+        tmpl1 = self.reg_env.get_template("b/justdict.html")
+        tmpl2 = self.mod_env.get_template("b/justdict.html")
         assert tmpl1.render() == tmpl2.render()
 
     def test_deflated_zip_compile(self, prefix_loader):
-        self.compile_down(prefix_loader, zip='deflated')
+        self.compile_down(prefix_loader, zip="deflated")
         self._test_common()
 
     def test_stored_zip_compile(self, prefix_loader):
-        self.compile_down(prefix_loader, zip='stored')
+        self.compile_down(prefix_loader, zip="stored")
         self._test_common()
 
     def test_filesystem_compile(self, prefix_loader):
@@ -248,8 +254,8 @@ class TestModuleLoader(object):
 
     def test_weak_references(self, prefix_loader):
         self.compile_down(prefix_loader)
-        tmpl = self.mod_env.get_template('a/test.html')
-        key = loaders.ModuleLoader.get_template_key('a/test.html')
+        tmpl = self.mod_env.get_template("a/test.html")
+        key = loaders.ModuleLoader.get_template_key("a/test.html")
         name = self.mod_env.loader.module.__name__
 
         assert hasattr(self.mod_env.loader.module, key)
@@ -260,6 +266,7 @@ class TestModuleLoader(object):
 
         try:
             import gc
+
             gc.collect()
         except:
             pass
@@ -268,65 +275,64 @@ class TestModuleLoader(object):
 
     # This test only makes sense on non-pypy python 2
     @pytest.mark.skipif(
-        not (PY2 and not PYPY),
-        reason='This test only makes sense on non-pypy python 2')
+        not (PY2 and not PYPY), reason="This test only makes sense on non-pypy python 2"
+    )
     def test_byte_compilation(self, prefix_loader):
         log = self.compile_down(prefix_loader, py_compile=True)
         assert 'Byte-compiled "a/test.html"' in log
-        tmpl1 = self.mod_env.get_template('a/test.html')
-        mod = self.mod_env.loader.module. \
-            tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
-        assert mod.__file__.endswith('.pyc')
+        tmpl1 = self.mod_env.get_template("a/test.html")
+        mod = self.mod_env.loader.module.tmpl_3c4ddf650c1a73df961a6d3d2ce2752f1b8fd490
+        assert mod.__file__.endswith(".pyc")
 
     def test_choice_loader(self, prefix_loader):
         log = self.compile_down(prefix_loader)
 
-        self.mod_env.loader = loaders.ChoiceLoader([
-            self.mod_env.loader,
-            loaders.DictLoader({'DICT_SOURCE': 'DICT_TEMPLATE'})
-        ])
+        self.mod_env.loader = loaders.ChoiceLoader(
+            [self.mod_env.loader, loaders.DictLoader({"DICT_SOURCE": "DICT_TEMPLATE"})]
+        )
 
-        tmpl1 = self.mod_env.get_template('a/test.html')
-        assert tmpl1.render() == 'BAR'
-        tmpl2 = self.mod_env.get_template('DICT_SOURCE')
-        assert tmpl2.render() == 'DICT_TEMPLATE'
+        tmpl1 = self.mod_env.get_template("a/test.html")
+        assert tmpl1.render() == "BAR"
+        tmpl2 = self.mod_env.get_template("DICT_SOURCE")
+        assert tmpl2.render() == "DICT_TEMPLATE"
 
     def test_prefix_loader(self, prefix_loader):
         log = self.compile_down(prefix_loader)
 
-        self.mod_env.loader = loaders.PrefixLoader({
-            'MOD':      self.mod_env.loader,
-            'DICT':     loaders.DictLoader({'test.html': 'DICT_TEMPLATE'})
-        })
+        self.mod_env.loader = loaders.PrefixLoader(
+            {
+                "MOD": self.mod_env.loader,
+                "DICT": loaders.DictLoader({"test.html": "DICT_TEMPLATE"}),
+            }
+        )
 
-        tmpl1 = self.mod_env.get_template('MOD/a/test.html')
-        assert tmpl1.render() == 'BAR'
-        tmpl2 = self.mod_env.get_template('DICT/test.html')
-        assert tmpl2.render() == 'DICT_TEMPLATE'
+        tmpl1 = self.mod_env.get_template("MOD/a/test.html")
+        assert tmpl1.render() == "BAR"
+        tmpl2 = self.mod_env.get_template("DICT/test.html")
+        assert tmpl2.render() == "DICT_TEMPLATE"
 
-    @pytest.mark.skipif(PY2, reason='pathlib is not available in Python 2')
+    @pytest.mark.skipif(PY2, reason="pathlib is not available in Python 2")
     def test_path_as_pathlib(self, prefix_loader):
         self.compile_down(prefix_loader)
 
         mod_path = self.mod_env.loader.module.__path__[0]
 
         import pathlib
+
         mod_loader = loaders.ModuleLoader(pathlib.Path(mod_path))
         self.mod_env = Environment(loader=mod_loader)
 
         self._test_common()
 
-    @pytest.mark.skipif(PY2, reason='pathlib is not available in Python 2')
+    @pytest.mark.skipif(PY2, reason="pathlib is not available in Python 2")
     def test_supports_pathlib_in_list_of_paths(self, prefix_loader):
         self.compile_down(prefix_loader)
 
         mod_path = self.mod_env.loader.module.__path__[0]
 
         import pathlib
-        mod_loader = loaders.ModuleLoader([
-            pathlib.Path(mod_path),
-            '/tmp/templates'
-        ])
+
+        mod_loader = loaders.ModuleLoader([pathlib.Path(mod_path), "/tmp/templates"])
         self.mod_env = Environment(loader=mod_loader)
 
         self._test_common()
index 6761a5f46f0f062928fdd984746ce0f6189aa754..77d378d27d44ef95f1705d233a9ae1739d1b8c5e 100644 (file)
@@ -13,17 +13,17 @@ def env():
 
 
 def test_is_defined_native_return(env):
-    t = env.from_string('{{ missing is defined }}')
+    t = env.from_string("{{ missing is defined }}")
     assert not t.render()
 
 
 def test_undefined_native_return(env):
-    t = env.from_string('{{ missing }}')
+    t = env.from_string("{{ missing }}")
     assert isinstance(t.render(), Undefined)
 
 
 def test_adding_undefined_native_return(env):
-    t = env.from_string('{{ 3 + missing }}')
+    t = env.from_string("{{ 3 + missing }}")
 
     with pytest.raises(UndefinedError):
         t.render()
@@ -31,30 +31,30 @@ def test_adding_undefined_native_return(env):
 
 def test_cast_int(env):
     t = env.from_string("{{ value|int }}")
-    result = t.render(value='3')
+    result = t.render(value="3")
     assert isinstance(result, int)
     assert result == 3
 
 
 def test_list_add(env):
     t = env.from_string("{{ a + b }}")
-    result = t.render(a=['a', 'b'], b=['c', 'd'])
+    result = t.render(a=["a", "b"], b=["c", "d"])
     assert isinstance(result, list)
-    assert result == ['a', 'b', 'c', 'd']
+    assert result == ["a", "b", "c", "d"]
 
 
 def test_multi_expression_add(env):
     t = env.from_string("{{ a }} + {{ b }}")
-    result = t.render(a=['a', 'b'], b=['c', 'd'])
+    result = t.render(a=["a", "b"], b=["c", "d"])
     assert not isinstance(result, list)
     assert result == "['a', 'b'] + ['c', 'd']"
 
 
 def test_loops(env):
     t = env.from_string("{% for x in value %}{{ x }}{% endfor %}")
-    result = t.render(value=['a', 'b', 'c', 'd'])
+    result = t.render(value=["a", "b", "c", "d"])
     assert isinstance(result, text_type)
-    assert result == 'abcd'
+    assert result == "abcd"
 
 
 def test_loops_with_ints(env):
@@ -71,14 +71,17 @@ def test_loop_look_alike(env):
     assert result == 1
 
 
-@pytest.mark.parametrize(("source", "expect"), (
-    ("{{ value }}", True),
-    ("{{ value }}", False),
-    ("{{ 1 == 1 }}", True),
-    ("{{ 2 + 2 == 5 }}", False),
-    ("{{ None is none }}", True),
-    ("{{ '' == None }}", False),
-))
+@pytest.mark.parametrize(
+    ("source", "expect"),
+    (
+        ("{{ value }}", True),
+        ("{{ value }}", False),
+        ("{{ 1 == 1 }}", True),
+        ("{{ 2 + 2 == 5 }}", False),
+        ("{{ None is none }}", True),
+        ("{{ '' == None }}", False),
+    ),
+)
 def test_booleans(env, source, expect):
     t = env.from_string(source)
     result = t.render(value=expect)
@@ -115,7 +118,7 @@ def test_string_literal_var(env):
 def test_string_top_level(env):
     t = env.from_string("'Jinja'")
     result = t.render()
-    assert result == 'Jinja'
+    assert result == "Jinja"
 
 
 def test_tuple_of_variable_strings(env):
index df91785df66c6b67c6918376190e943742a25a17..47e007324b9681d601528c8a499cf07562250e67 100644 (file)
@@ -24,94 +24,109 @@ from jinja2._compat import text_type
 
 @pytest.mark.regression
 class TestCorner(object):
-
     def test_assigned_scoping(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- for item in (1, 2, 3, 4) -%}
             [{{ item }}]
         {%- endfor %}
         {{- item -}}
-        ''')
-        assert t.render(item=42) == '[1][2][3][4]42'
+        """
+        )
+        assert t.render(item=42) == "[1][2][3][4]42"
 
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- for item in (1, 2, 3, 4) -%}
             [{{ item }}]
         {%- endfor %}
         {%- set item = 42 %}
         {{- item -}}
-        ''')
-        assert t.render() == '[1][2][3][4]42'
+        """
+        )
+        assert t.render() == "[1][2][3][4]42"
 
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- set item = 42 %}
         {%- for item in (1, 2, 3, 4) -%}
             [{{ item }}]
         {%- endfor %}
         {{- item -}}
-        ''')
-        assert t.render() == '[1][2][3][4]42'
+        """
+        )
+        assert t.render() == "[1][2][3][4]42"
 
     def test_closure_scoping(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- set wrapper = "<FOO>" %}
         {%- for item in (1, 2, 3, 4) %}
             {%- macro wrapper() %}[{{ item }}]{% endmacro %}
             {{- wrapper() }}
         {%- endfor %}
         {{- wrapper -}}
-        ''')
-        assert t.render() == '[1][2][3][4]<FOO>'
+        """
+        )
+        assert t.render() == "[1][2][3][4]<FOO>"
 
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- for item in (1, 2, 3, 4) %}
             {%- macro wrapper() %}[{{ item }}]{% endmacro %}
             {{- wrapper() }}
         {%- endfor %}
         {%- set wrapper = "<FOO>" %}
         {{- wrapper -}}
-        ''')
-        assert t.render() == '[1][2][3][4]<FOO>'
+        """
+        )
+        assert t.render() == "[1][2][3][4]<FOO>"
 
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {%- for item in (1, 2, 3, 4) %}
             {%- macro wrapper() %}[{{ item }}]{% endmacro %}
             {{- wrapper() }}
         {%- endfor %}
         {{- wrapper -}}
-        ''')
-        assert t.render(wrapper=23) == '[1][2][3][4]23'
+        """
+        )
+        assert t.render(wrapper=23) == "[1][2][3][4]23"
 
 
 @pytest.mark.regression
 class TestBug(object):
-
     def test_keyword_folding(self, env):
         env = Environment()
-        env.filters['testing'] = lambda value, some: value + some
-        assert env.from_string("{{ 'test'|testing(some='stuff') }}") \
-            .render() == 'teststuff'
+        env.filters["testing"] = lambda value, some: value + some
+        assert (
+            env.from_string("{{ 'test'|testing(some='stuff') }}").render()
+            == "teststuff"
+        )
 
     def test_extends_output_bugs(self, env):
-        env = Environment(loader=DictLoader({
-            'parent.html': '(({% block title %}{% endblock %}))'
-        }))
+        env = Environment(
+            loader=DictLoader({"parent.html": "(({% block title %}{% endblock %}))"})
+        )
 
         t = env.from_string(
             '{% if expr %}{% extends "parent.html" %}{% endif %}'
-            '[[{% block title %}title{% endblock %}]]'
-            '{% for item in [1, 2, 3] %}({{ item }}){% endfor %}'
+            "[[{% block title %}title{% endblock %}]]"
+            "{% for item in [1, 2, 3] %}({{ item }}){% endfor %}"
         )
-        assert t.render(expr=False) == '[[title]](1)(2)(3)'
-        assert t.render(expr=True) == '((title))'
+        assert t.render(expr=False) == "[[title]](1)(2)(3)"
+        assert t.render(expr=True) == "((title))"
 
     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/&lt;foo" rel="noopener">'\
-            'http://www.example.org/&lt;foo</a>'
+        assert (
+            tmpl.render() == '<a href="http://www.example.org/&lt;foo" rel="noopener">'
+            "http://www.example.org/&lt;foo</a>"
+        )
 
     def test_loop_call_loop(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
 
         {% macro test() %}
             {{ caller() }}
@@ -125,29 +140,35 @@ class TestBug(object):
             {% endcall %}
         {% endfor %}
 
-        ''')
+        """
+        )
 
-        assert tmpl.render().split() \
-            == [text_type(x) for x in range(1, 11)] * 5
+        assert tmpl.render().split() == [text_type(x) for x in range(1, 11)] * 5
 
     def test_weird_inline_comment(self, env):
-        env = Environment(line_statement_prefix='%')
-        pytest.raises(TemplateSyntaxError, env.from_string,
-                      '% for item in seq {# missing #}\n...% endfor')
+        env = Environment(line_statement_prefix="%")
+        pytest.raises(
+            TemplateSyntaxError,
+            env.from_string,
+            "% for item in seq {# missing #}\n...% endfor",
+        )
 
     def test_old_macro_loop_scoping_bug(self, env):
-        tmpl = env.from_string('{% for i in (1, 2) %}{{ i }}{% endfor %}'
-                               '{% macro i() %}3{% endmacro %}{{ i() }}')
-        assert tmpl.render() == '123'
+        tmpl = env.from_string(
+            "{% for i in (1, 2) %}{{ i }}{% endfor %}"
+            "{% macro i() %}3{% endmacro %}{{ i() }}"
+        )
+        assert tmpl.render() == "123"
 
     def test_partial_conditional_assignments(self, env):
-        tmpl = env.from_string('{% if b %}{% set a = 42 %}{% endif %}{{ a }}')
-        assert tmpl.render(a=23) == '23'
-        assert tmpl.render(b=True) == '42'
+        tmpl = env.from_string("{% if b %}{% set a = 42 %}{% endif %}{{ a }}")
+        assert tmpl.render(a=23) == "23"
+        assert tmpl.render(b=True) == "42"
 
     def test_stacked_locals_scoping_bug(self, env):
-        env = Environment(line_statement_prefix='#')
-        t = env.from_string('''\
+        env = Environment(line_statement_prefix="#")
+        t = env.from_string(
+            """\
 # for j in [1, 2]:
 #   set x = 1
 #   for i in [1, 2]:
@@ -166,11 +187,13 @@ class TestBug(object):
 # else
 #   print 'D'
 # endif
-    ''')
-        assert t.render(a=0, b=False, c=42, d=42.0) == '1111C'
+    """
+        )
+        assert t.render(a=0, b=False, c=42, d=42.0) == "1111C"
 
     def test_stacked_locals_scoping_bug_twoframe(self, env):
-        t = Template('''
+        t = Template(
+            """
             {% set x = 1 %}
             {% for item in foo %}
                 {% if item == 1 %}
@@ -178,12 +201,14 @@ class TestBug(object):
                 {% endif %}
             {% endfor %}
             {{ x }}
-        ''')
+        """
+        )
         rv = t.render(foo=[1]).strip()
-        assert rv == u'1'
+        assert rv == u"1"
 
     def test_call_with_args(self, env):
-        t = Template("""{% macro dump_users(users) -%}
+        t = Template(
+            """{% macro dump_users(users) -%}
         <ul>
           {%- for user in users -%}
             <li><p>{{ user.username|e }}</p>{{ caller(user) }}</li>
@@ -198,32 +223,40 @@ class TestBug(object):
             <dl>Description</dl>
             <dd>{{ user.description }}</dd>
           </dl>
-        {% endcall %}""")
-
-        assert [x.strip() for x in t.render(list_of_user=[{
-            'username': 'apo',
-            'realname': 'something else',
-            'description': 'test'
-        }]).splitlines()] == [
-            u'<ul><li><p>apo</p><dl>',
-            u'<dl>Realname</dl>',
-            u'<dd>something else</dd>',
-            u'<dl>Description</dl>',
-            u'<dd>test</dd>',
-            u'</dl>',
-            u'</li></ul>'
+        {% endcall %}"""
+        )
+
+        assert [
+            x.strip()
+            for x in t.render(
+                list_of_user=[
+                    {
+                        "username": "apo",
+                        "realname": "something else",
+                        "description": "test",
+                    }
+                ]
+            ).splitlines()
+        ] == [
+            u"<ul><li><p>apo</p><dl>",
+            u"<dl>Realname</dl>",
+            u"<dd>something else</dd>",
+            u"<dl>Description</dl>",
+            u"<dd>test</dd>",
+            u"</dl>",
+            u"</li></ul>",
         ]
 
     def test_empty_if_condition_fails(self, env):
-        pytest.raises(TemplateSyntaxError,
-                      Template, '{% if %}....{% endif %}')
-        pytest.raises(TemplateSyntaxError,
-                      Template, '{% if foo %}...{% elif %}...{% endif %}')
-        pytest.raises(TemplateSyntaxError,
-                      Template, '{% for x in %}..{% endfor %}')
+        pytest.raises(TemplateSyntaxError, Template, "{% if %}....{% endif %}")
+        pytest.raises(
+            TemplateSyntaxError, Template, "{% if foo %}...{% elif %}...{% endif %}"
+        )
+        pytest.raises(TemplateSyntaxError, Template, "{% for x in %}..{% endfor %}")
 
     def test_recursive_loop_bug(self, env):
-        tpl1 = Template("""
+        tpl1 = Template(
+            """
         {% for p in foo recursive%}
             {{p.bar}}
             {% for f in p.fields recursive%}
@@ -234,9 +267,11 @@ class TestBug(object):
                 {% endif %}
             {% endfor %}
         {% endfor %}
-        """)
+        """
+        )
 
-        tpl2 = Template("""
+        tpl2 = Template(
+            """
         {% for p in foo%}
             {{p.bar}}
             {% for f in p.fields recursive%}
@@ -247,26 +282,27 @@ class TestBug(object):
                 {% endif %}
             {% endfor %}
         {% endfor %}
-        """)
+        """
+        )
 
     def test_else_loop_bug(self, env):
-        t = Template('''
+        t = Template(
+            """
             {% for x in y %}
                 {{ loop.index0 }}
             {% else %}
                 {% for i in range(3) %}{{ i }}{% endfor %}
             {% endfor %}
-        ''')
-        assert t.render(y=[]).strip() == '012'
+        """
+        )
+        assert t.render(y=[]).strip() == "012"
 
     def test_correct_prefix_loader_name(self, env):
-        env = Environment(loader=PrefixLoader({
-            'foo':  DictLoader({})
-        }))
+        env = Environment(loader=PrefixLoader({"foo": DictLoader({})}))
         with pytest.raises(TemplateNotFound) as e:
-            env.get_template('foo/bar.html')
+            env.get_template("foo/bar.html")
 
-        assert e.value.name == 'foo/bar.html'
+        assert e.value.name == "foo/bar.html"
 
     def test_contextfunction_callable_classes(self, env):
         from jinja2.utils import contextfunction
@@ -274,74 +310,84 @@ class TestBug(object):
         class CallableClass(object):
             @contextfunction
             def __call__(self, ctx):
-                return ctx.resolve('hello')
+                return ctx.resolve("hello")
 
         tpl = Template("""{{ callableclass() }}""")
-        output = tpl.render(callableclass=CallableClass(), hello='TEST')
-        expected = 'TEST'
+        output = tpl.render(callableclass=CallableClass(), hello="TEST")
+        expected = "TEST"
 
         assert output == expected
 
-    @pytest.mark.skipif(sys.version_info[0] > 2,
-                        reason='This only works on 2.x')
+    @pytest.mark.skipif(sys.version_info[0] > 2, reason="This only works on 2.x")
     def test_old_style_attribute(self, env):
         class Foo:
             x = 42
-        assert env.getitem(Foo(), 'x') == 42
+
+        assert env.getitem(Foo(), "x") == 42
 
     def test_block_set_with_extends(self):
-        env = Environment(loader=DictLoader({
-            'main': '{% block body %}[{{ x }}]{% endblock %}',
-        }))
+        env = Environment(
+            loader=DictLoader({"main": "{% block body %}[{{ x }}]{% endblock %}",})
+        )
         t = env.from_string('{% extends "main" %}{% set x %}42{% endset %}')
-        assert t.render() == '[42]'
+        assert t.render() == "[42]"
 
     def test_nested_for_else(self, env):
-        tmpl = env.from_string('{% for x in y %}{{ loop.index0 }}{% else %}'
-                               '{% for i in range(3) %}{{ i }}{% endfor %}'
-                               '{% endfor %}')
-        assert tmpl.render() == '012'
+        tmpl = env.from_string(
+            "{% for x in y %}{{ loop.index0 }}{% else %}"
+            "{% for i in range(3) %}{{ i }}{% endfor %}"
+            "{% endfor %}"
+        )
+        assert tmpl.render() == "012"
 
     def test_macro_var_bug(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
         {% set i = 1 %}
         {% macro test() %}
             {% for i in range(0, 10) %}{{ i }}{% endfor %}
         {% endmacro %}{{ test() }}
-        ''')
-        assert tmpl.render().strip() == '0123456789'
+        """
+        )
+        assert tmpl.render().strip() == "0123456789"
 
     def test_macro_var_bug_advanced(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
         {% macro outer() %}
             {% set i = 1 %}
             {% macro test() %}
                 {% for i in range(0, 10) %}{{ i }}{% endfor %}
             {% endmacro %}{{ test() }}
         {% endmacro %}{{ outer() }}
-        ''')
-        assert tmpl.render().strip() == '0123456789'
+        """
+        )
+        assert tmpl.render().strip() == "0123456789"
 
     def test_callable_defaults(self):
         env = Environment()
-        env.globals['get_int'] = lambda: 42
-        t = env.from_string('''
+        env.globals["get_int"] = lambda: 42
+        t = env.from_string(
+            """
         {% macro test(a, b, c=get_int()) -%}
              {{ a + b + c }}
         {%- endmacro %}
         {{ test(1, 2) }}|{{ test(1, 2, 3) }}
-        ''')
-        assert t.render().strip() == '45|6'
+        """
+        )
+        assert t.render().strip() == "45|6"
 
     def test_macro_escaping(self):
         env = Environment(
-            autoescape=lambda x: False, extensions=['jinja2.ext.autoescape'])
+            autoescape=lambda x: False, extensions=["jinja2.ext.autoescape"]
+        )
         template = "{% macro m() %}<html>{% endmacro %}"
         template += "{% autoescape true %}{{ m() }}{% endautoescape %}"
         assert env.from_string(template).render()
 
     def test_macro_scoping(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
         {% set n=[1,2,3,4,5] %}
         {% for n in [[1,2,3], [3,4,5], [5,6,7]] %}
 
@@ -353,47 +399,56 @@ class TestBug(object):
         {{ x(n) }}
 
         {% endfor %}
-        ''')
-        assert list(map(int, tmpl.render().split())) == \
-            [3, 2, 1, 5, 4, 3, 7, 6, 5]
+        """
+        )
+        assert list(map(int, tmpl.render().split())) == [3, 2, 1, 5, 4, 3, 7, 6, 5]
 
     def test_scopes_and_blocks(self):
-        env = Environment(loader=DictLoader({
-            'a.html': '''
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "a.html": """
                 {%- set foo = 'bar' -%}
                 {% include 'x.html' -%}
-            ''',
-            'b.html': '''
+            """,
+                    "b.html": """
                 {%- set foo = 'bar' -%}
                 {% block test %}{% include 'x.html' %}{% endblock -%}
-                ''',
-            'c.html': '''
+                """,
+                    "c.html": """
                 {%- set foo = 'bar' -%}
                 {% block test %}{% set foo = foo
                     %}{% include 'x.html' %}{% endblock -%}
-            ''',
-            'x.html': '''{{ foo }}|{{ test }}'''
-        }))
+            """,
+                    "x.html": """{{ foo }}|{{ test }}""",
+                }
+            )
+        )
 
-        a = env.get_template('a.html')
-        b = env.get_template('b.html')
-        c = env.get_template('c.html')
+        a = env.get_template("a.html")
+        b = env.get_template("b.html")
+        c = env.get_template("c.html")
 
-        assert a.render(test='x').strip() == 'bar|x'
-        assert b.render(test='x').strip() == 'bar|x'
-        assert c.render(test='x').strip() == 'bar|x'
+        assert a.render(test="x").strip() == "bar|x"
+        assert b.render(test="x").strip() == "bar|x"
+        assert c.render(test="x").strip() == "bar|x"
 
     def test_scopes_and_include(self):
-        env = Environment(loader=DictLoader({
-            'include.html': '{{ var }}',
-            'base.html': '{% include "include.html" %}',
-            'child.html': '{% extends "base.html" %}{% set var = 42 %}',
-        }))
-        t = env.get_template('child.html')
-        assert t.render() == '42'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "include.html": "{{ var }}",
+                    "base.html": '{% include "include.html" %}',
+                    "child.html": '{% extends "base.html" %}{% set var = 42 %}',
+                }
+            )
+        )
+        t = env.get_template("child.html")
+        assert t.render() == "42"
 
     def test_caller_scoping(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         {% macro detail(icon, value) -%}
           {% if value -%}
             <p><span class="fa fa-fw fa-{{ icon }}"></span>
@@ -411,54 +466,67 @@ class TestBug(object):
             <a href="{{ href }}">{{ value }}</a>
           {%- endcall %}
         {%- endmacro %}
-        ''')
+        """
+        )
 
-        assert t.module.link_detail('circle', 'Index', '/') == (
-            '<p><span class="fa fa-fw fa-circle">'
-            '</span><a href="/">Index</a></p>')
+        assert t.module.link_detail("circle", "Index", "/") == (
+            '<p><span class="fa fa-fw fa-circle"></span><a href="/">Index</a></p>'
+        )
 
     def test_variable_reuse(self, env):
-        t = env.from_string('{% for x in x.y %}{{ x }}{% endfor %}')
-        assert t.render(x={'y': [0, 1, 2]}) == '012'
+        t = env.from_string("{% for x in x.y %}{{ x }}{% endfor %}")
+        assert t.render(x={"y": [0, 1, 2]}) == "012"
 
-        t = env.from_string('{% for x in x.y %}{{ loop.index0 }}|{{ x }}{% endfor %}')
-        assert t.render(x={'y': [0, 1, 2]}) == '0|01|12|2'
+        t = env.from_string("{% for x in x.y %}{{ loop.index0 }}|{{ x }}{% endfor %}")
+        assert t.render(x={"y": [0, 1, 2]}) == "0|01|12|2"
 
-        t = env.from_string('{% for x in x.y recursive %}{{ x }}{% endfor %}')
-        assert t.render(x={'y': [0, 1, 2]}) == '012'
+        t = env.from_string("{% for x in x.y recursive %}{{ x }}{% endfor %}")
+        assert t.render(x={"y": [0, 1, 2]}) == "012"
 
     def test_double_caller(self, env):
-        t = env.from_string('{% macro x(caller=none) %}[{% if caller %}'
-                            '{{ caller() }}{% endif %}]{% endmacro %}'
-                            '{{ x() }}{% call x() %}aha!{% endcall %}')
-        assert t.render() == '[][aha!]'
+        t = env.from_string(
+            "{% macro x(caller=none) %}[{% if caller %}"
+            "{{ caller() }}{% endif %}]{% endmacro %}"
+            "{{ x() }}{% call x() %}aha!{% endcall %}"
+        )
+        assert t.render() == "[][aha!]"
 
     def test_double_caller_no_default(self, env):
         with pytest.raises(TemplateAssertionError) as exc_info:
-            env.from_string('{% macro x(caller) %}[{% if caller %}'
-                            '{{ caller() }}{% endif %}]{% endmacro %}')
-        assert exc_info.match(r'"caller" argument must be omitted or '
-                              r'be given a default')
+            env.from_string(
+                "{% macro x(caller) %}[{% if caller %}"
+                "{{ caller() }}{% endif %}]{% endmacro %}"
+            )
+        assert exc_info.match(
+            r'"caller" argument must be omitted or ' r"be given a default"
+        )
 
-        t = env.from_string('{% macro x(caller=none) %}[{% if caller %}'
-                            '{{ caller() }}{% endif %}]{% endmacro %}')
+        t = env.from_string(
+            "{% macro x(caller=none) %}[{% if caller %}"
+            "{{ caller() }}{% endif %}]{% endmacro %}"
+        )
         with pytest.raises(TypeError) as exc_info:
             t.module.x(None, caller=lambda: 42)
-        assert exc_info.match(r'\'x\' was invoked with two values for the '
-                              r'special caller argument')
+        assert exc_info.match(
+            r"\'x\' was invoked with two values for the " r"special caller argument"
+        )
 
     def test_macro_blocks(self, env):
-        t = env.from_string('{% macro x() %}{% block foo %}x{% '
-                            'endblock %}{% endmacro %}{{ x() }}')
-        assert t.render() == 'x'
+        t = env.from_string(
+            "{% macro x() %}{% block foo %}x{% endblock %}{% endmacro %}{{ x() }}"
+        )
+        assert t.render() == "x"
 
     def test_scoped_block(self, env):
-        t = env.from_string('{% set x = 1 %}{% with x = 2 %}{% block y scoped %}'
-                            '{{ x }}{% endblock %}{% endwith %}')
-        assert t.render() == '2'
+        t = env.from_string(
+            "{% set x = 1 %}{% with x = 2 %}{% block y scoped %}"
+            "{{ x }}{% endblock %}{% endwith %}"
+        )
+        assert t.render() == "2"
 
     def test_recursive_loop_filter(self, env):
-        t = env.from_string('''
+        t = env.from_string(
+            """
         <?xml version="1.0" encoding="UTF-8"?>
         <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
           {%- for page in [site.root] if page.url != this recursive %}
@@ -466,49 +534,65 @@ class TestBug(object):
           {{- loop(page.children) }}
           {%- endfor %}
         </urlset>
-        ''')
-        sm  =t.render(this='/foo', site={'root': {
-            'url': '/',
-            'children': [
-                {'url': '/foo'},
-                {'url': '/bar'},
-            ]
-        }})
+        """
+        )
+        sm = t.render(
+            this="/foo",
+            site={
+                "root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"},]}
+            },
+        )
         lines = [x.strip() for x in sm.splitlines() if x.strip()]
         assert lines == [
             '<?xml version="1.0" encoding="UTF-8"?>',
             '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',
-            '<url><loc>/</loc></url>',
-            '<url><loc>/bar</loc></url>',
-            '</urlset>',
+            "<url><loc>/</loc></url>",
+            "<url><loc>/bar</loc></url>",
+            "</urlset>",
         ]
 
     def test_empty_if(self, env):
-        t = env.from_string('{% if foo %}{% else %}42{% endif %}')
-        assert t.render(foo=False) == '42'
+        t = env.from_string("{% if foo %}{% else %}42{% endif %}")
+        assert t.render(foo=False) == "42"
 
     def test_subproperty_if(self, env):
-        t = env.from_string('{% if object1.subproperty1 is eq object2.subproperty2 %}42{% endif %}')
-        assert t.render(object1={'subproperty1': 'value'}, object2={'subproperty2': 'value'}) == '42'
+        t = env.from_string(
+            "{% if object1.subproperty1 is eq object2.subproperty2 %}42{% endif %}"
+        )
+        assert (
+            t.render(
+                object1={"subproperty1": "value"}, object2={"subproperty2": "value"}
+            )
+            == "42"
+        )
 
     def test_set_and_include(self):
-        env = Environment(loader=DictLoader({
-            'inc': 'bar',
-            'main': '{% set foo = "foo" %}{{ foo }}{% include "inc" %}'
-        }))
-        assert env.get_template('main').render() == 'foobar'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "inc": "bar",
+                    "main": '{% set foo = "foo" %}{{ foo }}{% include "inc" %}',
+                }
+            )
+        )
+        assert env.get_template("main").render() == "foobar"
 
     def test_loop_include(self):
-        env = Environment(loader=DictLoader({
-            'inc': '{{ item }}',
-            'main': '{% for item in [1, 2, 3] %}{% include "inc" %}{% endfor %}',
-        }))
-        assert env.get_template('main').render() == '123'
+        env = Environment(
+            loader=DictLoader(
+                {
+                    "inc": "{{ item }}",
+                    "main": '{% for item in [1, 2, 3] %}{% include "inc" %}{% endfor %}',
+                }
+            )
+        )
+        assert env.get_template("main").render() == "123"
 
     def test_grouper_repr(self):
         from jinja2.filters import _GroupTuple
-        t = _GroupTuple('foo', [1, 2])
-        assert t.grouper == 'foo'
+
+        t = _GroupTuple("foo", [1, 2])
+        assert t.grouper == "foo"
         assert t.list == [1, 2]
         assert repr(t) == "('foo', [1, 2])"
         assert str(t) == "('foo', [1, 2])"
@@ -522,33 +606,35 @@ class TestBug(object):
         class MyEnvironment(Environment):
             context_class = MyContext
 
-        loader = DictLoader({'base': '{{ foobar }}',
-                             'test': '{% extends "base" %}'})
+        loader = DictLoader({"base": "{{ foobar }}", "test": '{% extends "base" %}'})
         env = MyEnvironment(loader=loader)
-        assert env.get_template('test').render(foobar='test') == 'test'
+        assert env.get_template("test").render(foobar="test") == "test"
 
     def test_legacy_custom_context(self, env):
         from jinja2.runtime import Context, Undefined, missing
 
         class MyContext(Context):
             def resolve(self, name):
-                if name == 'foo':
+                if name == "foo":
                     return 42
                 return super(MyContext, self).resolve(name)
 
-        x = MyContext(env, parent={'bar': 23}, name='foo', blocks={})
+        x = MyContext(env, parent={"bar": 23}, name="foo", blocks={})
         assert x._legacy_resolve_mode
-        assert x.resolve_or_missing('foo') == 42
-        assert x.resolve_or_missing('bar') == 23
-        assert x.resolve_or_missing('baz') is missing
+        assert x.resolve_or_missing("foo") == 42
+        assert x.resolve_or_missing("bar") == 23
+        assert x.resolve_or_missing("baz") is missing
 
     def test_recursive_loop_bug(self, env):
-        tmpl = env.from_string('''
+        tmpl = env.from_string(
+            """
             {%- for value in values recursive %}1{% else %}0{% endfor -%}
-        ''')
-        assert tmpl.render(values=[]) == '0'
+        """
+        )
+        assert tmpl.render(values=[]) == "0"
 
     def test_markup_and_chainable_undefined(self):
         from jinja2 import Markup
         from jinja2.runtime import ChainableUndefined
-        assert str(Markup(ChainableUndefined())) == ''
+
+        assert str(Markup(ChainableUndefined())) == ""
index 1afcb3fad5ef1ebc002bbce0eb569d92e41d1b91..307f0550d041630d3f4554c9ee56f6d29460621e 100644 (file)
@@ -52,9 +52,9 @@ def test_loopcontext2():
 
 def test_iterator_not_advanced_early():
     t = Template("{% for _, g in gs %}{{ loop.index }} {{ g|list }}\n{% endfor %}")
-    out = t.render(gs=itertools.groupby(
-        [(1, "a"), (1, "b"), (2, "c"), (3, "d")], lambda x: x[0]
-    ))
+    out = t.render(
+        gs=itertools.groupby([(1, "a"), (1, "b"), (2, "c"), (3, "d")], lambda x: x[0])
+    )
     # groupby groups depend on the current position of the iterator. If
     # it was advanced early, the lists would appear empty.
     assert out == "1 [(1, 'a'), (1, 'b')]\n2 [(2, 'c')]\n3 [(3, 'd')]\n"
index b37b655541754399dd65dec6156f1a8b25922389..39045fd458ebf803cd84df0f91c628cb129548fb 100644 (file)
@@ -24,7 +24,6 @@ from jinja2.sandbox import unsafe
 
 
 class PrivateStuff(object):
-
     def bar(self):
         return 23
 
@@ -33,7 +32,7 @@ class PrivateStuff(object):
         return 42
 
     def __repr__(self):
-        return 'PrivateStuff'
+        return "PrivateStuff"
 
 
 class PublicStuff(object):
@@ -41,57 +40,64 @@ class PublicStuff(object):
     _foo = lambda self: 42
 
     def __repr__(self):
-        return 'PublicStuff'
+        return "PublicStuff"
 
 
 @pytest.mark.sandbox
 class TestSandbox(object):
-
     def test_unsafe(self, env):
         env = SandboxedEnvironment()
-        pytest.raises(SecurityError, env.from_string("{{ foo.foo() }}").render,
-                      foo=PrivateStuff())
-        assert env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()) == '23'
-
-        pytest.raises(SecurityError,
-                      env.from_string("{{ foo._foo() }}").render,
-                      foo=PublicStuff())
-        assert env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()) == '23'
-        assert env.from_string("{{ foo.__class__ }}").render(foo=42) == ''
-        assert env.from_string("{{ foo.func_code }}").render(foo=lambda:None) == ''
+        pytest.raises(
+            SecurityError, env.from_string("{{ foo.foo() }}").render, foo=PrivateStuff()
+        )
+        assert env.from_string("{{ foo.bar() }}").render(foo=PrivateStuff()) == "23"
+
+        pytest.raises(
+            SecurityError, env.from_string("{{ foo._foo() }}").render, foo=PublicStuff()
+        )
+        assert env.from_string("{{ foo.bar() }}").render(foo=PublicStuff()) == "23"
+        assert env.from_string("{{ foo.__class__ }}").render(foo=42) == ""
+        assert env.from_string("{{ foo.func_code }}").render(foo=lambda: None) == ""
         # security error comes from __class__ already.
-        pytest.raises(SecurityError, env.from_string(
-            "{{ foo.__class__.__subclasses__() }}").render, foo=42)
+        pytest.raises(
+            SecurityError,
+            env.from_string("{{ foo.__class__.__subclasses__() }}").render,
+            foo=42,
+        )
 
     def test_immutable_environment(self, env):
         env = ImmutableSandboxedEnvironment()
-        pytest.raises(SecurityError, env.from_string(
-            '{{ [].append(23) }}').render)
-        pytest.raises(SecurityError, env.from_string(
-            '{{ {1:2}.clear() }}').render)
+        pytest.raises(SecurityError, env.from_string("{{ [].append(23) }}").render)
+        pytest.raises(SecurityError, env.from_string("{{ {1:2}.clear() }}").render)
 
     def test_restricted(self, env):
         env = SandboxedEnvironment()
-        pytest.raises(TemplateSyntaxError, env.from_string,
-                      "{% for item.attribute in seq %}...{% endfor %}")
-        pytest.raises(TemplateSyntaxError, env.from_string,
-                      "{% for foo, bar.baz in seq %}...{% endfor %}")
+        pytest.raises(
+            TemplateSyntaxError,
+            env.from_string,
+            "{% for item.attribute in seq %}...{% endfor %}",
+        )
+        pytest.raises(
+            TemplateSyntaxError,
+            env.from_string,
+            "{% for foo, bar.baz in seq %}...{% endfor %}",
+        )
 
     def test_markup_operations(self, env):
         # adding two strings should escape the unsafe one
         unsafe = '<script type="application/x-some-script">alert("foo");</script>'
-        safe = Markup('<em>username</em>')
+        safe = Markup("<em>username</em>")
         assert unsafe + safe == text_type(escape(unsafe)) + text_type(safe)
 
         # string interpolations are safe to use too
-        assert Markup('<em>%s</em>') % '<bad user>' == \
-            '<em>&lt;bad user&gt;</em>'
-        assert Markup('<em>%(username)s</em>') % {
-            'username': '<bad user>'
-        } == '<em>&lt;bad user&gt;</em>'
+        assert Markup("<em>%s</em>") % "<bad user>" == "<em>&lt;bad user&gt;</em>"
+        assert (
+            Markup("<em>%(username)s</em>") % {"username": "<bad user>"}
+            == "<em>&lt;bad user&gt;</em>"
+        )
 
         # an escaped object is markup too
-        assert type(Markup('foo') + 'bar') is Markup
+        assert type(Markup("foo") + "bar") is Markup
 
         # and it implements __html__ by returning itself
         x = Markup("foo")
@@ -100,33 +106,38 @@ class TestSandbox(object):
         # it also knows how to treat __html__ objects
         class Foo(object):
             def __html__(self):
-                return '<em>awesome</em>'
+                return "<em>awesome</em>"
 
             def __unicode__(self):
-                return 'awesome'
-        assert Markup(Foo()) == '<em>awesome</em>'
-        assert Markup('<strong>%s</strong>') % Foo() == \
-            '<strong><em>awesome</em></strong>'
+                return "awesome"
+
+        assert Markup(Foo()) == "<em>awesome</em>"
+        assert (
+            Markup("<strong>%s</strong>") % Foo() == "<strong><em>awesome</em></strong>"
+        )
 
         # escaping and unescaping
-        assert escape('"<>&\'') == '&#34;&lt;&gt;&amp;&#39;'
+        assert escape("\"<>&'") == "&#34;&lt;&gt;&amp;&#39;"
         assert Markup("<em>Foo &amp; Bar</em>").striptags() == "Foo & Bar"
         assert Markup("&lt;test&gt;").unescape() == "<test>"
 
     def test_template_data(self, env):
         env = Environment(autoescape=True)
-        t = env.from_string('{% macro say_hello(name) %}'
-                            '<p>Hello {{ name }}!</p>{% endmacro %}'
-                            '{{ say_hello("<blink>foo</blink>") }}')
-        escaped_out = '<p>Hello &lt;blink&gt;foo&lt;/blink&gt;!</p>'
+        t = env.from_string(
+            "{% macro say_hello(name) %}"
+            "<p>Hello {{ name }}!</p>{% endmacro %}"
+            '{{ say_hello("<blink>foo</blink>") }}'
+        )
+        escaped_out = "<p>Hello &lt;blink&gt;foo&lt;/blink&gt;!</p>"
         assert t.render() == escaped_out
         assert text_type(t.module) == escaped_out
         assert escape(t.module) == escaped_out
-        assert t.module.say_hello('<blink>foo</blink>') == escaped_out
-        assert escape(t.module.say_hello(
-            EvalContext(env), '<blink>foo</blink>')) == escaped_out
-        assert escape(t.module.say_hello(
-            '<blink>foo</blink>')) == escaped_out
+        assert t.module.say_hello("<blink>foo</blink>") == escaped_out
+        assert (
+            escape(t.module.say_hello(EvalContext(env), "<blink>foo</blink>"))
+            == escaped_out
+        )
+        assert escape(t.module.say_hello("<blink>foo</blink>")) == escaped_out
 
     def test_attr_filter(self, env):
         env = SandboxedEnvironment()
@@ -135,69 +146,74 @@ class TestSandbox(object):
 
     def test_binary_operator_intercepting(self, env):
         def disable_op(left, right):
-            raise TemplateRuntimeError('that operator so does not work')
-        for expr, ctx, rv in ('1 + 2', {}, '3'), ('a + 2', {'a': 2}, '4'):
+            raise TemplateRuntimeError("that operator so does not work")
+
+        for expr, ctx, rv in ("1 + 2", {}, "3"), ("a + 2", {"a": 2}, "4"):
             env = SandboxedEnvironment()
-            env.binop_table['+'] = disable_op
-            t = env.from_string('{{ %s }}' % expr)
+            env.binop_table["+"] = disable_op
+            t = env.from_string("{{ %s }}" % expr)
             assert t.render(ctx) == rv
-            env.intercepted_binops = frozenset(['+'])
-            t = env.from_string('{{ %s }}' % expr)
+            env.intercepted_binops = frozenset(["+"])
+            t = env.from_string("{{ %s }}" % expr)
             with pytest.raises(TemplateRuntimeError):
                 t.render(ctx)
 
     def test_unary_operator_intercepting(self, env):
         def disable_op(arg):
-            raise TemplateRuntimeError('that operator so does not work')
-        for expr, ctx, rv in ('-1', {}, '-1'), ('-a', {'a': 2}, '-2'):
+            raise TemplateRuntimeError("that operator so does not work")
+
+        for expr, ctx, rv in ("-1", {}, "-1"), ("-a", {"a": 2}, "-2"):
             env = SandboxedEnvironment()
-            env.unop_table['-'] = disable_op
-            t = env.from_string('{{ %s }}' % expr)
+            env.unop_table["-"] = disable_op
+            t = env.from_string("{{ %s }}" % expr)
             assert t.render(ctx) == rv
-            env.intercepted_unops = frozenset(['-'])
-            t = env.from_string('{{ %s }}' % expr)
+            env.intercepted_unops = frozenset(["-"])
+            t = env.from_string("{{ %s }}" % expr)
             with pytest.raises(TemplateRuntimeError):
                 t.render(ctx)
 
 
 @pytest.mark.sandbox
 class TestStringFormat(object):
-
     def test_basic_format_safety(self):
         env = SandboxedEnvironment()
         t = env.from_string('{{ "a{0.__class__}b".format(42) }}')
-        assert t.render() == 'ab'
+        assert t.render() == "ab"
 
     def test_basic_format_all_okay(self):
         env = SandboxedEnvironment()
         t = env.from_string('{{ "a{0.foo}b".format({"foo": 42}) }}')
-        assert t.render() == 'a42b'
+        assert t.render() == "a42b"
 
     def test_safe_format_safety(self):
         env = SandboxedEnvironment()
         t = env.from_string('{{ ("a{0.__class__}b{1}"|safe).format(42, "<foo>") }}')
-        assert t.render() == 'ab&lt;foo&gt;'
+        assert t.render() == "ab&lt;foo&gt;"
 
     def test_safe_format_all_okay(self):
         env = SandboxedEnvironment()
         t = env.from_string('{{ ("a{0.foo}b{1}"|safe).format({"foo": 42}, "<foo>") }}')
-        assert t.render() == 'a42b&lt;foo&gt;'
+        assert t.render() == "a42b&lt;foo&gt;"
 
 
 @pytest.mark.sandbox
-@pytest.mark.skipif(not hasattr(str, 'format_map'), reason='requires str.format_map method')
+@pytest.mark.skipif(
+    not hasattr(str, "format_map"), reason="requires str.format_map method"
+)
 class TestStringFormatMap(object):
     def test_basic_format_safety(self):
         env = SandboxedEnvironment()
         t = env.from_string('{{ "a{x.__class__}b".format_map({"x":42}) }}')
-        assert t.render() == 'ab'
+        assert t.render() == "ab"
 
     def test_basic_format_all_okay(self):
         env = SandboxedEnvironment()
         t = env.from_string('{{ "a{x.foo}b".format_map({"x":{"foo": 42}}) }}')
-        assert t.render() == 'a42b'
+        assert t.render() == "a42b"
 
     def test_safe_format_all_okay(self):
         env = SandboxedEnvironment()
-        t = env.from_string('{{ ("a{x.foo}b{y}"|safe).format_map({"x":{"foo": 42}, "y":"<foo>"}) }}')
-        assert t.render() == 'a42b&lt;foo&gt;'
+        t = env.from_string(
+            '{{ ("a{x.foo}b{y}"|safe).format_map({"x":{"foo": 42}, "y":"<foo>"}) }}'
+        )
+        assert t.render() == "a42b&lt;foo&gt;"
index dd83efa1fcac42f6c3c7a03b0c1a7174fc2fa2db..27871ca22718bc4fc14cad2da78394fa203caf98 100644 (file)
@@ -13,208 +13,208 @@ import pytest
 from jinja2 import Environment
 from jinja2 import Markup
 
+
 class MyDict(dict):
     pass
 
+
 @pytest.mark.test_tests
 class TestTestsCase(object):
-
     def test_defined(self, env):
-        tmpl = env.from_string('{{ missing is defined }}|'
-                               '{{ true is defined }}')
-        assert tmpl.render() == 'False|True'
+        tmpl = env.from_string("{{ missing is defined }}|{{ true is defined }}")
+        assert tmpl.render() == "False|True"
 
     def test_even(self, env):
-        tmpl = env.from_string('''{{ 1 is even }}|{{ 2 is even }}''')
-        assert tmpl.render() == 'False|True'
+        tmpl = env.from_string("""{{ 1 is even }}|{{ 2 is even }}""")
+        assert tmpl.render() == "False|True"
 
     def test_odd(self, env):
-        tmpl = env.from_string('''{{ 1 is odd }}|{{ 2 is odd }}''')
-        assert tmpl.render() == 'True|False'
+        tmpl = env.from_string("""{{ 1 is odd }}|{{ 2 is odd }}""")
+        assert tmpl.render() == "True|False"
 
     def test_lower(self, env):
-        tmpl = env.from_string('''{{ "foo" is lower }}|{{ "FOO" is lower }}''')
-        assert tmpl.render() == 'True|False'
+        tmpl = env.from_string("""{{ "foo" is lower }}|{{ "FOO" is lower }}""")
+        assert tmpl.render() == "True|False"
 
     # Test type checks
-    @pytest.mark.parametrize('op,expect', (
-        ('none is none', True),
-        ('false is none', False),
-        ('true is none', False),
-        ('42 is none', False),
-
-        ('none is true', False),
-        ('false is true', False),
-        ('true is true', True),
-        ('0 is true', False),
-        ('1 is true', False),
-        ('42 is true', False),
-
-        ('none is false', False),
-        ('false is false', True),
-        ('true is false', False),
-        ('0 is false', False),
-        ('1 is false', False),
-        ('42 is false', False),
-
-        ('none is boolean', False),
-        ('false is boolean', True),
-        ('true is boolean', True),
-        ('0 is boolean', False),
-        ('1 is boolean', False),
-        ('42 is boolean', False),
-        ('0.0 is boolean', False),
-        ('1.0 is boolean', False),
-        ('3.14159 is boolean', False),
-
-        ('none is integer', False),
-        ('false is integer', False),
-        ('true is integer', False),
-        ('42 is integer', True),
-        ('3.14159 is integer', False),
-        ('(10 ** 100) is integer', True),
-
-        ('none is float', False),
-        ('false is float', False),
-        ('true is float', False),
-        ('42 is float', False),
-        ('4.2 is float', True),
-        ('(10 ** 100) is float', False),
-
-        ('none is number', False),
-        ('false is number', True),
-        ('true is number', True),
-        ('42 is number', True),
-        ('3.14159 is number', True),
-        ('complex is number', True),
-        ('(10 ** 100) is number', True),
-
-        ('none is string', False),
-        ('false is string', False),
-        ('true is string', False),
-        ('42 is string', False),
-        ('"foo" is string', True),
-
-        ('none is sequence', False),
-        ('false is sequence', False),
-        ('42 is sequence', False),
-        ('"foo" is sequence', True),
-        ('[] is sequence', True),
-        ('[1, 2, 3] is sequence', True),
-        ('{} is sequence', True),
-
-        ('none is mapping', False),
-        ('false is mapping', False),
-        ('42 is mapping', False),
-        ('"foo" is mapping', False),
-        ('[] is mapping', False),
-        ('{} is mapping', True),
-        ('mydict is mapping', True),
-
-        ('none is iterable', False),
-        ('false is iterable', False),
-        ('42 is iterable', False),
-        ('"foo" is iterable', True),
-        ('[] is iterable', True),
-        ('{} is iterable', True),
-        ('range(5) is iterable', True),
-
-        ('none is callable', False),
-        ('false is callable', False),
-        ('42 is callable', False),
-        ('"foo" is callable', False),
-        ('[] is callable', False),
-        ('{} is callable', False),
-        ('range is callable', True),
-    ))
+    @pytest.mark.parametrize(
+        "op,expect",
+        (
+            ("none is none", True),
+            ("false is none", False),
+            ("true is none", False),
+            ("42 is none", False),
+            ("none is true", False),
+            ("false is true", False),
+            ("true is true", True),
+            ("0 is true", False),
+            ("1 is true", False),
+            ("42 is true", False),
+            ("none is false", False),
+            ("false is false", True),
+            ("true is false", False),
+            ("0 is false", False),
+            ("1 is false", False),
+            ("42 is false", False),
+            ("none is boolean", False),
+            ("false is boolean", True),
+            ("true is boolean", True),
+            ("0 is boolean", False),
+            ("1 is boolean", False),
+            ("42 is boolean", False),
+            ("0.0 is boolean", False),
+            ("1.0 is boolean", False),
+            ("3.14159 is boolean", False),
+            ("none is integer", False),
+            ("false is integer", False),
+            ("true is integer", False),
+            ("42 is integer", True),
+            ("3.14159 is integer", False),
+            ("(10 ** 100) is integer", True),
+            ("none is float", False),
+            ("false is float", False),
+            ("true is float", False),
+            ("42 is float", False),
+            ("4.2 is float", True),
+            ("(10 ** 100) is float", False),
+            ("none is number", False),
+            ("false is number", True),
+            ("true is number", True),
+            ("42 is number", True),
+            ("3.14159 is number", True),
+            ("complex is number", True),
+            ("(10 ** 100) is number", True),
+            ("none is string", False),
+            ("false is string", False),
+            ("true is string", False),
+            ("42 is string", False),
+            ('"foo" is string', True),
+            ("none is sequence", False),
+            ("false is sequence", False),
+            ("42 is sequence", False),
+            ('"foo" is sequence', True),
+            ("[] is sequence", True),
+            ("[1, 2, 3] is sequence", True),
+            ("{} is sequence", True),
+            ("none is mapping", False),
+            ("false is mapping", False),
+            ("42 is mapping", False),
+            ('"foo" is mapping', False),
+            ("[] is mapping", False),
+            ("{} is mapping", True),
+            ("mydict is mapping", True),
+            ("none is iterable", False),
+            ("false is iterable", False),
+            ("42 is iterable", False),
+            ('"foo" is iterable', True),
+            ("[] is iterable", True),
+            ("{} is iterable", True),
+            ("range(5) is iterable", True),
+            ("none is callable", False),
+            ("false is callable", False),
+            ("42 is callable", False),
+            ('"foo" is callable', False),
+            ("[] is callable", False),
+            ("{} is callable", False),
+            ("range is callable", True),
+        ),
+    )
     def test_types(self, env, op, expect):
-        t = env.from_string('{{{{ {op} }}}}'.format(op=op))
+        t = env.from_string("{{{{ {op} }}}}".format(op=op))
         assert t.render(mydict=MyDict(), complex=complex(1, 2)) == str(expect)
 
-
     def test_upper(self, env):
         tmpl = env.from_string('{{ "FOO" is upper }}|{{ "foo" is upper }}')
-        assert tmpl.render() == 'True|False'
+        assert tmpl.render() == "True|False"
 
     def test_equalto(self, env):
         tmpl = env.from_string(
-            '{{ foo is eq 12 }}|'
-            '{{ foo is eq 0 }}|'
-            '{{ foo is eq (3 * 4) }}|'
+            "{{ foo is eq 12 }}|"
+            "{{ foo is eq 0 }}|"
+            "{{ foo is eq (3 * 4) }}|"
             '{{ bar is eq "baz" }}|'
             '{{ bar is eq "zab" }}|'
             '{{ bar is eq ("ba" + "z") }}|'
-            '{{ bar is eq bar }}|'
-            '{{ bar is eq foo }}'
+            "{{ bar is eq bar }}|"
+            "{{ bar is eq foo }}"
+        )
+        assert (
+            tmpl.render(foo=12, bar="baz")
+            == "True|False|True|True|False|True|True|False"
         )
-        assert tmpl.render(foo=12, bar="baz") \
-            == 'True|False|True|True|False|True|True|False'
-
-    @pytest.mark.parametrize('op,expect', (
-        ('eq 2', True),
-        ('eq 3', False),
-        ('ne 3', True),
-        ('ne 2', False),
-        ('lt 3', True),
-        ('lt 2', False),
-        ('le 2', True),
-        ('le 1', False),
-        ('gt 1', True),
-        ('gt 2', False),
-        ('ge 2', True),
-        ('ge 3', False),
-    ))
+
+    @pytest.mark.parametrize(
+        "op,expect",
+        (
+            ("eq 2", True),
+            ("eq 3", False),
+            ("ne 3", True),
+            ("ne 2", False),
+            ("lt 3", True),
+            ("lt 2", False),
+            ("le 2", True),
+            ("le 1", False),
+            ("gt 1", True),
+            ("gt 2", False),
+            ("ge 2", True),
+            ("ge 3", False),
+        ),
+    )
     def test_compare_aliases(self, env, op, expect):
-        t = env.from_string('{{{{ 2 is {op} }}}}'.format(op=op))
+        t = env.from_string("{{{{ 2 is {op} }}}}".format(op=op))
         assert t.render() == str(expect)
 
     def test_sameas(self, env):
-        tmpl = env.from_string('{{ foo is sameas false }}|'
-                               '{{ 0 is sameas false }}')
-        assert tmpl.render(foo=False) == 'True|False'
+        tmpl = env.from_string("{{ foo is sameas false }}|{{ 0 is sameas false }}")
+        assert tmpl.render(foo=False) == "True|False"
 
     def test_no_paren_for_arg1(self, env):
-        tmpl = env.from_string('{{ foo is sameas none }}')
-        assert tmpl.render(foo=None) == 'True'
+        tmpl = env.from_string("{{ foo is sameas none }}")
+        assert tmpl.render(foo=None) == "True"
 
     def test_escaped(self, env):
         env = Environment(autoescape=True)
-        tmpl = env.from_string('{{ x is escaped }}|{{ y is escaped }}')
-        assert tmpl.render(x='foo', y=Markup('foo')) == 'False|True'
+        tmpl = env.from_string("{{ x is escaped }}|{{ y is escaped }}")
+        assert tmpl.render(x="foo", y=Markup("foo")) == "False|True"
 
     def test_greaterthan(self, env):
-        tmpl = env.from_string('{{ 1 is greaterthan 0 }}|'
-                               '{{ 0 is greaterthan 1 }}')
-        assert tmpl.render() == 'True|False'
+        tmpl = env.from_string("{{ 1 is greaterthan 0 }}|{{ 0 is greaterthan 1 }}")
+        assert tmpl.render() == "True|False"
 
     def test_lessthan(self, env):
-        tmpl = env.from_string('{{ 0 is lessthan 1 }}|'
-                               '{{ 1 is lessthan 0 }}')
-        assert tmpl.render() == 'True|False'
+        tmpl = env.from_string("{{ 0 is lessthan 1 }}|{{ 1 is lessthan 0 }}")
+        assert tmpl.render() == "True|False"
 
     def test_multiple_tests(self):
         items = []
+
         def matching(x, y):
             items.append((x, y))
             return False
+
         env = Environment()
-        env.tests['matching'] = matching
-        tmpl = env.from_string("{{ 'us-west-1' is matching "
-                               "'(us-east-1|ap-northeast-1)' "
-                               "or 'stage' is matching '(dev|stage)' }}")
-        assert tmpl.render() == 'False'
-        assert items == [('us-west-1', '(us-east-1|ap-northeast-1)'),
-                         ('stage', '(dev|stage)')]
+        env.tests["matching"] = matching
+        tmpl = env.from_string(
+            "{{ 'us-west-1' is matching "
+            "'(us-east-1|ap-northeast-1)' "
+            "or 'stage' is matching '(dev|stage)' }}"
+        )
+        assert tmpl.render() == "False"
+        assert items == [
+            ("us-west-1", "(us-east-1|ap-northeast-1)"),
+            ("stage", "(dev|stage)"),
+        ]
 
     def test_in(self, env):
-        tmpl = env.from_string('{{ "o" is in "foo" }}|'
-                               '{{ "foo" is in "foo" }}|'
-                               '{{ "b" is in "foo" }}|'
-                               '{{ 1 is in ((1, 2)) }}|'
-                               '{{ 3 is in ((1, 2)) }}|'
-                               '{{ 1 is in [1, 2] }}|'
-                               '{{ 3 is in [1, 2] }}|'
-                               '{{ "foo" is in {"foo": 1}}}|'
-                               '{{ "baz" is in {"bar": 1}}}')
-        assert tmpl.render() \
-            == 'True|True|False|True|False|True|False|True|False'
+        tmpl = env.from_string(
+            '{{ "o" is in "foo" }}|'
+            '{{ "foo" is in "foo" }}|'
+            '{{ "b" is in "foo" }}|'
+            "{{ 1 is in ((1, 2)) }}|"
+            "{{ 3 is in ((1, 2)) }}|"
+            "{{ 1 is in [1, 2] }}|"
+            "{{ 3 is in [1, 2] }}|"
+            '{{ "foo" is in {"foo": 1}}}|'
+            '{{ "baz" is in {"bar": 1}}}'
+        )
+        assert tmpl.render() == "True|True|False|True|False|True|False|True|False"
index 15b6c55f8e191e61dee1a17c139f1c84cdebadaf..8cecb1b56d981dc42d0739beb794f9cff8bf5025 100644 (file)
@@ -30,7 +30,6 @@ from jinja2.utils import urlize
 @pytest.mark.utils
 @pytest.mark.lrucache
 class TestLRUCache(object):
-
     def test_simple(self):
         d = LRUCache(3)
         d["a"] = 1
@@ -39,7 +38,7 @@ class TestLRUCache(object):
         d["a"]
         d["d"] = 4
         assert len(d) == 3
-        assert 'a' in d and 'c' in d and 'd' in d and 'b' not in d
+        assert "a" in d and "c" in d and "d" in d and "b" not in d
 
     def test_itervalue_deprecated(self):
         cache = LRUCache(3)
@@ -77,13 +76,13 @@ class TestLRUCache(object):
     @pytest.mark.parametrize("copy_func", [LRUCache.copy, shallow_copy])
     def test_copy(self, copy_func):
         cache = LRUCache(2)
-        cache['a'] = 1
-        cache['b'] = 2
+        cache["a"] = 1
+        cache["b"] = 2
         copy = copy_func(cache)
         assert copy._queue == cache._queue
-        copy['c'] = 3
+        copy["c"] = 3
         assert copy._queue != cache._queue
-        assert 'a' not in copy and 'b' in copy and 'c' in copy
+        assert "a" not in copy and "b" in copy and "c" in copy
 
     def test_clear(self):
         d = LRUCache(3)
@@ -91,7 +90,7 @@ class TestLRUCache(object):
         d["b"] = 2
         d["c"] = 3
         d.clear()
-        assert d.__getstate__() == {'capacity': 3, '_mapping': {}, '_queue': deque([])}
+        assert d.__getstate__() == {"capacity": 3, "_mapping": {}, "_queue": deque([])}
 
     def test_repr(self):
         d = LRUCache(3)
@@ -107,18 +106,18 @@ class TestLRUCache(object):
         d["a"] = 1
         d["b"] = 2
         d["c"] = 3
-        assert d.items() == list(d.iteritems()) == [('c', 3), ('b', 2), ('a', 1)]
-        assert d.keys() == list(d.iterkeys()) == ['c', 'b', 'a']
+        assert d.items() == list(d.iteritems()) == [("c", 3), ("b", 2), ("a", 1)]
+        assert d.keys() == list(d.iterkeys()) == ["c", "b", "a"]
         assert d.values() == list(d.itervalues()) == [3, 2, 1]
-        assert list(reversed(d)) == ['a', 'b', 'c']
+        assert list(reversed(d)) == ["a", "b", "c"]
 
         # Change the cache a little
         d["b"]
         d["a"] = 4
-        assert d.items() == list(d.iteritems()) == [('a', 4), ('b', 2), ('c', 3)]
-        assert d.keys() == list(d.iterkeys()) == ['a', 'b', 'c']
+        assert d.items() == list(d.iteritems()) == [("a", 4), ("b", 2), ("c", 3)]
+        assert d.keys() == list(d.iterkeys()) == ["a", "b", "c"]
         assert d.values() == list(d.itervalues()) == [4, 2, 3]
-        assert list(reversed(d)) == ['c', 'b', 'a']
+        assert list(reversed(d)) == ["c", "b", "a"]
 
     def test_setdefault(self):
         d = LRUCache(3)
@@ -133,31 +132,31 @@ class TestLRUCache(object):
 @pytest.mark.utils
 @pytest.mark.helpers
 class TestHelpers(object):
-
     def test_object_type_repr(self):
         class X(object):
             pass
-        assert object_type_repr(42) == 'int object'
-        assert object_type_repr([]) == 'list object'
-        assert object_type_repr(X()) == 'test_utils.X object'
-        assert object_type_repr(None) == 'None'
-        assert object_type_repr(Ellipsis) == 'Ellipsis'
+
+        assert object_type_repr(42) == "int object"
+        assert object_type_repr([]) == "list object"
+        assert object_type_repr(X()) == "test_utils.X object"
+        assert object_type_repr(None) == "None"
+        assert object_type_repr(Ellipsis) == "Ellipsis"
 
     def test_autoescape_select(self):
         func = select_autoescape(
-            enabled_extensions=('html', '.htm'),
-            disabled_extensions=('txt',),
-            default_for_string='STRING',
-            default='NONE',
+            enabled_extensions=("html", ".htm"),
+            disabled_extensions=("txt",),
+            default_for_string="STRING",
+            default="NONE",
         )
 
-        assert func(None) == 'STRING'
-        assert func('unknown.foo') == 'NONE'
-        assert func('foo.html') == True
-        assert func('foo.htm') == True
-        assert func('foo.txt') == False
-        assert func('FOO.HTML') == True
-        assert func('FOO.TXT') == False
+        assert func(None) == "STRING"
+        assert func("unknown.foo") == "NONE"
+        assert func("foo.html") == True
+        assert func("foo.htm") == True
+        assert func("foo.txt") == False
+        assert func("FOO.HTML") == True
+        assert func("FOO.TXT") == False
 
 
 @pytest.mark.utils
@@ -166,9 +165,11 @@ class TestEscapeUrlizeTarget(object):
     def test_escape_urlize_target(self):
         url = "http://example.org"
         target = "<script>"
-        assert urlize(url, target=target) == ('<a href="http://example.org"'
-                                              ' target="&lt;script&gt;">'
-                                              'http://example.org</a>')
+        assert urlize(url, target=target) == (
+            '<a href="http://example.org"'
+            ' target="&lt;script&gt;">'
+            "http://example.org</a>"
+        )
 
 
 @pytest.mark.utils
@@ -184,28 +185,29 @@ class TestLoremIpsum(object):
 
     def test_lorem_ipsum_n(self):
         """Test that the n (number of lines) works as expected."""
-        assert generate_lorem_ipsum(n=0, html=False) == u''
+        assert generate_lorem_ipsum(n=0, html=False) == u""
         for n in range_type(1, 50):
-            assert generate_lorem_ipsum(n=n, html=False).count('\n') == (n - 1) * 2
+            assert generate_lorem_ipsum(n=n, html=False).count("\n") == (n - 1) * 2
 
     def test_lorem_ipsum_min(self):
         """Test that at least min words are in the output of each line"""
         for _ in range_type(5):
-           m = random.randrange(20, 99)
-           for _ in range_type(10):
-               assert generate_lorem_ipsum(n=1, min=m, html=False).count(' ') >= m - 1
+            m = random.randrange(20, 99)
+            for _ in range_type(10):
+                assert generate_lorem_ipsum(n=1, min=m, html=False).count(" ") >= m - 1
 
     def test_lorem_ipsum_max(self):
         """Test that at least max words are in the output of each line"""
         for _ in range_type(5):
-           m = random.randrange(21, 100)
-           for _ in range_type(10):
-               assert generate_lorem_ipsum(n=1, max=m, html=False).count(' ') < m - 1
+            m = random.randrange(21, 100)
+            for _ in range_type(10):
+                assert generate_lorem_ipsum(n=1, max=m, html=False).count(" ") < m - 1
 
 
 def test_missing():
     """Test the repr of missing."""
-    assert repr(missing) == u'missing'
+    assert repr(missing) == u"missing"
+
 
 def test_consume():
     """Test that consume consumes an iterator."""