apply flake8
This commit is contained in:
parent
04c8787155
commit
bb6216ea30
@ -6,9 +6,9 @@ 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 %}""",
|
||||
"a": "[A[{% block body %}{% endblock %}]]",
|
||||
"b": "{% extends 'a' %}{% block body %}[B]{% endblock %}",
|
||||
"c": "{% extends 'b' %}{% block body %}###{{ super() }}###{% endblock %}",
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
@ -12,7 +12,9 @@ print(
|
||||
env.from_string(
|
||||
"""\
|
||||
{% trans %}Hello {{ user }}!{% endtrans %}
|
||||
{% trans count=users|count %}{{ count }} user{% pluralize %}{{ count }} users{% endtrans %}
|
||||
{% trans count=users|count -%}
|
||||
{{ count }} user{% pluralize %}{{ count }} users
|
||||
{% endtrans %}
|
||||
"""
|
||||
).render(user="someone", users=[1, 2, 3])
|
||||
)
|
||||
|
||||
@ -8,6 +8,7 @@ import sys
|
||||
from timeit import Timer
|
||||
|
||||
from jinja2 import Environment as JinjaEnvironment
|
||||
from jinja2._compat import text_type
|
||||
|
||||
context = {
|
||||
"page_title": "mitsuhiko's benchmark",
|
||||
@ -171,7 +172,8 @@ else:
|
||||
<h1>${page_title|h}</h1>
|
||||
</div>
|
||||
<ul class="navigation">
|
||||
% for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
|
||||
% for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), \
|
||||
('products.html', 'Products')]:
|
||||
<li><a href="${href|h}">${caption|h}</a></li>
|
||||
% endfor
|
||||
</ul>
|
||||
@ -250,7 +252,8 @@ else:
|
||||
<h1>$cgi.escape($page_title)</h1>
|
||||
</div>
|
||||
<ul class="navigation">
|
||||
#for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]:
|
||||
#for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), \
|
||||
('products.html', 'Products')]:
|
||||
<li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
|
||||
#end for
|
||||
</ul>
|
||||
@ -272,7 +275,7 @@ else:
|
||||
)
|
||||
|
||||
def test_cheetah():
|
||||
unicode(cheetah_template)
|
||||
text_type(cheetah_template)
|
||||
|
||||
|
||||
try:
|
||||
@ -293,7 +296,8 @@ else:
|
||||
<h1>${page_title}</h1>
|
||||
</div>
|
||||
<ul class="navigation">
|
||||
<?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]: ?>
|
||||
<?py for href, caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), \
|
||||
('products.html', 'Products')]: ?>
|
||||
<li><a href="${href}">${caption}</a></li>
|
||||
<?py #end ?>
|
||||
</ul>
|
||||
@ -314,8 +318,6 @@ else:
|
||||
)
|
||||
|
||||
def test_tenjin():
|
||||
from tenjin.helpers import escape, to_str
|
||||
|
||||
tenjin_template.render(context, locals())
|
||||
|
||||
|
||||
@ -337,7 +339,8 @@ else:
|
||||
<h1>$cgi.escape($page_title)</h1>
|
||||
</div>
|
||||
<ul class="navigation">
|
||||
#for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), ('products.html', 'Products')]
|
||||
#for $href, $caption in [('index.html', 'Index'), ('downloads.html', 'Downloads'), \
|
||||
('products.html', 'Products')]
|
||||
<li><a href="$cgi.escape($href)">$cgi.escape($caption)</a></li>
|
||||
#end for
|
||||
</ul>
|
||||
@ -381,7 +384,8 @@ else:
|
||||
<h1 tal:content="page_title">Page Title</h1>
|
||||
</div>
|
||||
<ul class="navigation">
|
||||
<li tal:repeat="item sections"><a tal:attributes="href item[0]" tal:content="item[1]">caption</a></li>
|
||||
<li tal:repeat="item sections"><a tal:attributes="href item[0]" \
|
||||
tal:content="item[1]">caption</a></li>
|
||||
</ul>
|
||||
<div class="table">
|
||||
<table>
|
||||
|
||||
@ -1,72 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Django to Jinja
|
||||
~~~~~~~~~~~~~~~
|
||||
Django to Jinja
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Helper module that can convert django templates into Jinja templates.
|
||||
Helper module that can convert django templates into Jinja templates.
|
||||
|
||||
This file is not intended to be used as stand alone application but to
|
||||
be used as library. To convert templates you basically create your own
|
||||
writer, add extra conversion logic for your custom template tags,
|
||||
configure your django environment and run the `convert_templates`
|
||||
function.
|
||||
This file is not intended to be used as stand alone application but to
|
||||
be used as library. To convert templates you basically create your own
|
||||
writer, add extra conversion logic for your custom template tags,
|
||||
configure your django environment and run the `convert_templates`
|
||||
function.
|
||||
|
||||
Here a simple example::
|
||||
Here a simple example::
|
||||
|
||||
# configure django (or use settings.configure)
|
||||
import os
|
||||
os.environ['DJANGO_SETTINGS_MODULE'] = 'yourapplication.settings'
|
||||
from yourapplication.foo.templatetags.bar import MyNode
|
||||
# configure django (or use settings.configure)
|
||||
import os
|
||||
|
||||
from django2jinja import Writer, convert_templates
|
||||
os.environ["DJANGO_SETTINGS_MODULE"] = "yourapplication.settings"
|
||||
from yourapplication.foo.templatetags.bar import MyNode
|
||||
|
||||
def write_my_node(writer, node):
|
||||
writer.start_variable()
|
||||
writer.write('myfunc(')
|
||||
for idx, arg in enumerate(node.args):
|
||||
if idx:
|
||||
writer.write(', ')
|
||||
writer.node(arg)
|
||||
writer.write(')')
|
||||
writer.end_variable()
|
||||
from django2jinja import Writer, convert_templates
|
||||
|
||||
writer = Writer()
|
||||
writer.node_handlers[MyNode] = write_my_node
|
||||
convert_templates('/path/to/output/folder', writer=writer)
|
||||
def write_my_node(writer, node):
|
||||
writer.start_variable()
|
||||
writer.write("myfunc(")
|
||||
for idx, arg in enumerate(node.args):
|
||||
if idx:
|
||||
writer.write(", ")
|
||||
writer.node(arg)
|
||||
writer.write(")")
|
||||
writer.end_variable()
|
||||
|
||||
Here is an example hos to automatically translate your django
|
||||
variables to jinja2::
|
||||
writer = Writer()
|
||||
writer.node_handlers[MyNode] = write_my_node
|
||||
convert_templates("/path/to/output/folder", writer=writer)
|
||||
|
||||
import re
|
||||
# List of tuple (Match pattern, Replace pattern, Exclusion pattern)
|
||||
Here is an example hos to automatically translate your django
|
||||
variables to jinja2::
|
||||
|
||||
var_re = ((re.compile(r"(u|user)\.is_authenticated"), r"\1.is_authenticated()", None),
|
||||
(re.compile(r"\.non_field_errors"), r".non_field_errors()", None),
|
||||
(re.compile(r"\.label_tag"), r".label_tag()", None),
|
||||
(re.compile(r"\.as_dl"), r".as_dl()", None),
|
||||
(re.compile(r"\.as_table"), r".as_table()", None),
|
||||
(re.compile(r"\.as_widget"), r".as_widget()", None),
|
||||
(re.compile(r"\.as_hidden"), r".as_hidden()", None),
|
||||
import re
|
||||
# List of tuple (Match pattern, Replace pattern, Exclusion pattern)
|
||||
var_re = (
|
||||
(re.compile("(u|user)\\.is_authenticated"), "\\1.is_authenticated()", None),
|
||||
(re.compile("\\.non_field_errors"), ".non_field_errors()", None),
|
||||
(re.compile("\\.label_tag"), ".label_tag()", None),
|
||||
(re.compile("\\.as_dl"), ".as_dl()", None),
|
||||
(re.compile("\\.as_table"), ".as_table()", None),
|
||||
(re.compile("\\.as_widget"), ".as_widget()", None),
|
||||
(re.compile("\\.as_hidden"), ".as_hidden()", None),
|
||||
(re.compile("\\.get_([0-9_\\w]+)_url"), ".get_\\1_url()", None),
|
||||
(re.compile("\\.url"), ".url()", re.compile("(form|calendar).url")),
|
||||
(re.compile("\\.get_([0-9_\\w]+)_display"), ".get_\\1_display()", None),
|
||||
(re.compile("loop\\.counte"), "loop.index", None),
|
||||
(re.compile("loop\\.revcounte"), "loop.revindex", None),
|
||||
(
|
||||
re.compile("request\\.GET\\.([0-9_\\w]+)"),
|
||||
"request.GET.get('\\1', '')",
|
||||
None,
|
||||
),
|
||||
(re.compile("request\\.get_host"), "request.get_host()", None),
|
||||
(re.compile("\\.all(?!_)"), ".all()", None),
|
||||
(re.compile("\\.all\\.0"), ".all()[0]", None),
|
||||
(re.compile("\\.([0-9])($|\\s+)"), "[\\1]\\2", None),
|
||||
(re.compile("\\.items"), ".items()", None),
|
||||
)
|
||||
writer = Writer(var_re=var_re)
|
||||
|
||||
(re.compile(r"\.get_([0-9_\w]+)_url"), r".get_\1_url()", None),
|
||||
(re.compile(r"\.url"), r".url()", re.compile(r"(form|calendar).url")),
|
||||
(re.compile(r"\.get_([0-9_\w]+)_display"), r".get_\1_display()", None),
|
||||
(re.compile(r"loop\.counter"), r"loop.index", None),
|
||||
(re.compile(r"loop\.revcounter"), r"loop.revindex", None),
|
||||
(re.compile(r"request\.GET\.([0-9_\w]+)"), r"request.GET.get('\1', '')", None),
|
||||
(re.compile(r"request\.get_host"), r"request.get_host()", None),
|
||||
For details about the writing process have a look at the module code.
|
||||
|
||||
(re.compile(r"\.all(?!_)"), r".all()", None),
|
||||
(re.compile(r"\.all\.0"), r".all()[0]", None),
|
||||
(re.compile(r"\.([0-9])($|\s+)"), r"[\1]\2", None),
|
||||
(re.compile(r"\.items"), r".items()", None),
|
||||
)
|
||||
writer = Writer(var_re=var_re)
|
||||
|
||||
For details about the writing process have a look at the module code.
|
||||
|
||||
:copyright: (c) 2009 by the Jinja Team.
|
||||
:license: BSD.
|
||||
:copyright: (c) 2009 by the Jinja Team.
|
||||
:license: BSD.
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
@ -87,14 +90,12 @@ from django.template import Variable
|
||||
from django.template.debug import DebugVariableNode as VariableNode
|
||||
from django.templatetags import i18n as i18n_tags
|
||||
|
||||
from jinja2.defaults import *
|
||||
|
||||
from jinja2 import defaults
|
||||
|
||||
_node_handlers = {}
|
||||
_resolved_filters = {}
|
||||
_newline_re = re.compile(r"(?:\r\n|\r|\n)")
|
||||
|
||||
|
||||
# Django stores an itertools object on the cycle node. Not only is this
|
||||
# thread unsafe but also a problem for the converter which needs the raw
|
||||
# string values passed to the constructor to create a jinja loop.cycle()
|
||||
@ -122,7 +123,8 @@ 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.
|
||||
translates them and writes the new templates into the output
|
||||
directory.
|
||||
"""
|
||||
if writer is None:
|
||||
writer = Writer()
|
||||
@ -156,11 +158,8 @@ def convert_templates(
|
||||
if not os.path.exists(basetarget):
|
||||
os.makedirs(basetarget)
|
||||
callback(source)
|
||||
f = file(target, "w")
|
||||
try:
|
||||
with open(target, "w") as f:
|
||||
translate(f, source)
|
||||
finally:
|
||||
f.close()
|
||||
|
||||
|
||||
class Writer(object):
|
||||
@ -170,16 +169,16 @@ class Writer(object):
|
||||
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,
|
||||
block_start_string=defaults.BLOCK_START_STRING,
|
||||
block_end_string=defaults.BLOCK_END_STRING,
|
||||
variable_start_string=defaults.VARIABLE_START_STRING,
|
||||
variable_end_string=defaults.VARIABLE_END_STRING,
|
||||
comment_start_string=defaults.COMMENT_START_STRING,
|
||||
comment_end_string=defaults.COMMENT_END_STRING,
|
||||
initial_autoescape=True,
|
||||
use_jinja_autoescape=False,
|
||||
custom_node_handlers=None,
|
||||
var_re=[],
|
||||
var_re=None,
|
||||
env=None,
|
||||
):
|
||||
if stream is None:
|
||||
@ -200,12 +199,12 @@ class Writer(object):
|
||||
self.node_handlers = dict(_node_handlers, **(custom_node_handlers or {}))
|
||||
self._loop_depth = 0
|
||||
self._filters_warned = set()
|
||||
self.var_re = var_re
|
||||
self.var_re = [] if var_re is None else var_re
|
||||
self.env = env
|
||||
|
||||
def enter_loop(self):
|
||||
"""Increments the loop depth so that write functions know if they
|
||||
are in a loop.
|
||||
"""Increments the loop depth so that write functions know if
|
||||
they are in a loop.
|
||||
"""
|
||||
self._loop_depth += 1
|
||||
|
||||
@ -223,7 +222,9 @@ class Writer(object):
|
||||
self.stream.write(s.encode(settings.FILE_CHARSET))
|
||||
|
||||
def print_expr(self, expr):
|
||||
"""Open a variable tag, write to the string to the stream and close."""
|
||||
"""Open a variable tag, write to the string to the stream and
|
||||
close.
|
||||
"""
|
||||
self.start_variable()
|
||||
self.write(expr)
|
||||
self.end_variable()
|
||||
@ -269,7 +270,9 @@ class Writer(object):
|
||||
self.end_block()
|
||||
|
||||
def variable(self, name):
|
||||
"""Prints a variable. This performs variable name transformation."""
|
||||
"""Prints a variable. This performs variable name
|
||||
transformation.
|
||||
"""
|
||||
self.write(self.translate_variable_name(name))
|
||||
|
||||
def literal(self, value):
|
||||
@ -287,7 +290,10 @@ class Writer(object):
|
||||
if name is None:
|
||||
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 defaults.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)
|
||||
if not want_pipe:
|
||||
@ -344,13 +350,13 @@ class Writer(object):
|
||||
"""
|
||||
if filter not in _resolved_filters:
|
||||
for library in libraries.values():
|
||||
for key, value in library.filters.iteritems():
|
||||
for key, value in library.filters.items():
|
||||
_resolved_filters[value] = key
|
||||
return _resolved_filters.get(filter, None)
|
||||
|
||||
def node(self, node):
|
||||
"""Invokes the node handler for a node."""
|
||||
for cls, handler in self.node_handlers.iteritems():
|
||||
for cls, handler in self.node_handlers.items():
|
||||
if type(node) is cls or type(node).__name__ == cls:
|
||||
handler(self, node)
|
||||
break
|
||||
@ -410,7 +416,7 @@ def comment_tag(writer, node):
|
||||
|
||||
|
||||
@node(core_tags.DebugNode)
|
||||
def comment_tag(writer, node):
|
||||
def debug_tag(writer, node):
|
||||
writer.warn(
|
||||
"Debug tag detected. Make sure to add a global function "
|
||||
"called debug to the namespace.",
|
||||
@ -596,7 +602,6 @@ def url_tag(writer, node):
|
||||
writer.write("set %s = " % node.asvar)
|
||||
else:
|
||||
writer.start_variable()
|
||||
autoescape = writer.autoescape
|
||||
writer.write("url(")
|
||||
writer.literal(node.view_name)
|
||||
for arg in node.args:
|
||||
@ -740,10 +745,7 @@ def translate_block(writer, node):
|
||||
touch_var(key)
|
||||
writer.node(var.filter_expression)
|
||||
|
||||
have_plural = False
|
||||
plural_var = None
|
||||
if node.plural and node.countervar and node.counter:
|
||||
have_plural = True
|
||||
plural_var = node.countervar
|
||||
if plural_var not in variables:
|
||||
if idx > -1:
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
from django.conf import settings
|
||||
from django2jinja import convert_templates
|
||||
from django2jinja import Writer
|
||||
|
||||
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)
|
||||
|
||||
@ -10,9 +10,9 @@ if sys.version_info[0] < 3:
|
||||
|
||||
def get_characters():
|
||||
"""Find every Unicode character that is valid in a Python `identifier`_ but
|
||||
is not matched by the regex ``\w`` group.
|
||||
is not matched by the regex ``\\w`` group.
|
||||
|
||||
``\w`` matches some characters that aren't valid in identifiers, but
|
||||
``\\w`` matches some characters that aren't valid in identifiers, but
|
||||
:meth:`str.isidentifier` will catch that later in lexing.
|
||||
|
||||
All start characters are valid continue characters, so we only test for
|
||||
@ -33,7 +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 _, b in itertools.groupby(enumerate(data), lambda x: ord(x[1]) - x[0]):
|
||||
b = list(b)
|
||||
yield b[0][1], b[-1][1]
|
||||
|
||||
@ -66,8 +66,9 @@ def main():
|
||||
)
|
||||
|
||||
with open(filename, "w", encoding="utf8") as f:
|
||||
f.write("")
|
||||
f.write("# generated by scripts/generate_identifier_pattern.py\n")
|
||||
f.write('pattern = "{}"\n'.format(pattern))
|
||||
f.write('pattern = "{}" # noqa: B950\n'.format(pattern))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@ -27,7 +27,7 @@ def parse_changelog():
|
||||
with open("CHANGES.rst") as f:
|
||||
lineiter = iter(f)
|
||||
for line in lineiter:
|
||||
match = re.search("^Version\s+(.*)", line.strip())
|
||||
match = re.search(r"^Version\s+(.*)", line.strip())
|
||||
|
||||
if match is None:
|
||||
continue
|
||||
@ -161,7 +161,7 @@ def main():
|
||||
fail("You have uncommitted changes in git")
|
||||
|
||||
try:
|
||||
import wheel
|
||||
__import__("wheel")
|
||||
except ImportError:
|
||||
fail("You need to install the wheel package.")
|
||||
|
||||
|
||||
@ -37,3 +37,6 @@ ignore =
|
||||
W503
|
||||
# up to 88 allowed by bugbear B950
|
||||
max-line-length = 80
|
||||
per-file-ignores =
|
||||
# __init__ module exports names
|
||||
src/jinja2/__init__.py: F401
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# flake8: noqa
|
||||
"""
|
||||
jinja2._compat
|
||||
~~~~~~~~~~~~~~
|
||||
@ -10,6 +11,7 @@
|
||||
:copyright: Copyright 2013 by the Jinja team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import marshal
|
||||
import sys
|
||||
|
||||
PY2 = sys.version_info[0] == 2
|
||||
@ -46,6 +48,9 @@ if not PY2:
|
||||
implements_to_string = _identity
|
||||
encode_filename = _identity
|
||||
|
||||
marshal_dump = marshal.dump
|
||||
marshal_load = marshal.load
|
||||
|
||||
else:
|
||||
unichr = unichr
|
||||
text_type = unicode
|
||||
@ -83,6 +88,17 @@ else:
|
||||
return filename.encode("utf-8")
|
||||
return filename
|
||||
|
||||
def marshal_dump(code, f):
|
||||
if isinstance(f, file):
|
||||
marshal.dump(code, f)
|
||||
else:
|
||||
f.write(marshal.dumps(code))
|
||||
|
||||
def marshal_load(f):
|
||||
if isinstance(f, file):
|
||||
return marshal.load(f)
|
||||
return marshal.loads(f.read())
|
||||
|
||||
|
||||
def with_metaclass(meta, *bases):
|
||||
"""Create a base class with a metaclass."""
|
||||
|
||||
@ -1,2 +1,2 @@
|
||||
# generated by scripts/generate_identifier_pattern.py
|
||||
pattern = "·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯"
|
||||
pattern = "·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯" # noqa: B950
|
||||
|
||||
@ -27,14 +27,19 @@ 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):
|
||||
is_async = lambda args: args[0].is_async
|
||||
|
||||
def is_async(args):
|
||||
return args[0].is_async
|
||||
|
||||
wrap_evalctx = False
|
||||
else:
|
||||
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
|
||||
|
||||
def is_async(args):
|
||||
return args[0].environment.is_async
|
||||
|
||||
@wraps(normal_filter)
|
||||
def wrapper(*args, **kwargs):
|
||||
@ -123,7 +128,10 @@ async def do_sum(environment, iterable, attribute=None, start=0):
|
||||
if attribute is not None:
|
||||
func = filters.make_attrgetter(environment, attribute)
|
||||
else:
|
||||
func = lambda x: x
|
||||
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
async for item in auto_aiter(iterable):
|
||||
rv += func(item)
|
||||
return rv
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
"""
|
||||
import errno
|
||||
import fnmatch
|
||||
import marshal
|
||||
import os
|
||||
import stat
|
||||
import sys
|
||||
@ -26,29 +25,12 @@ from os import listdir
|
||||
from os import path
|
||||
|
||||
from ._compat import BytesIO
|
||||
from ._compat import marshal_dump
|
||||
from ._compat import marshal_load
|
||||
from ._compat import pickle
|
||||
from ._compat import PY2
|
||||
from ._compat import text_type
|
||||
from .utils import open_if_exists
|
||||
|
||||
# marshal works better on 3.x, one hack less required
|
||||
if not PY2:
|
||||
marshal_dump = marshal.dump
|
||||
marshal_load = marshal.load
|
||||
else:
|
||||
|
||||
def marshal_dump(code, f):
|
||||
if isinstance(f, file):
|
||||
marshal.dump(code, f)
|
||||
else:
|
||||
f.write(marshal.dumps(code))
|
||||
|
||||
def marshal_load(f):
|
||||
if isinstance(f, file):
|
||||
return marshal.load(f)
|
||||
return marshal.loads(f.read())
|
||||
|
||||
|
||||
bc_version = 3
|
||||
|
||||
# magic version used to only change with new jinja versions. With 2.6
|
||||
|
||||
@ -549,10 +549,10 @@ class CodeGenerator(NodeVisitor):
|
||||
else:
|
||||
args.append(frame.symbols.declare_parameter("caller"))
|
||||
macro_ref.accesses_caller = True
|
||||
if "kwargs" in undeclared and not "kwargs" in skip_special_params:
|
||||
if "kwargs" in undeclared and "kwargs" not 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:
|
||||
if "varargs" in undeclared and "varargs" not in skip_special_params:
|
||||
args.append(frame.symbols.declare_parameter("varargs"))
|
||||
macro_ref.accesses_varargs = True
|
||||
|
||||
@ -1242,7 +1242,6 @@ class CodeGenerator(NodeVisitor):
|
||||
if frame.toplevel:
|
||||
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.macro_def(macro_ref, macro_frame)
|
||||
@ -1270,7 +1269,7 @@ class CodeGenerator(NodeVisitor):
|
||||
with_frame = frame.inner()
|
||||
with_frame.symbols.analyze_node(node)
|
||||
self.enter_frame(with_frame)
|
||||
for idx, (target, expr) in enumerate(izip(node.targets, node.values)):
|
||||
for target, expr in izip(node.targets, node.values):
|
||||
self.newline()
|
||||
self.visit(target, with_frame)
|
||||
self.write(" = ")
|
||||
@ -1317,7 +1316,7 @@ class CodeGenerator(NodeVisitor):
|
||||
|
||||
if getattr(env_finalize, "contextfunction", False):
|
||||
src += "context, "
|
||||
finalize = None
|
||||
finalize = None # noqa: F811
|
||||
elif getattr(env_finalize, "evalcontextfunction", False):
|
||||
src += "context.eval_ctx, "
|
||||
finalize = None
|
||||
@ -1570,7 +1569,7 @@ class CodeGenerator(NodeVisitor):
|
||||
self.visit(item.value, frame)
|
||||
self.write("}")
|
||||
|
||||
def binop(operator, interceptable=True):
|
||||
def binop(operator, interceptable=True): # noqa: B902
|
||||
@optimizeconst
|
||||
def visitor(self, node, frame):
|
||||
if (
|
||||
@ -1590,7 +1589,7 @@ class CodeGenerator(NodeVisitor):
|
||||
|
||||
return visitor
|
||||
|
||||
def uaop(operator, interceptable=True):
|
||||
def uaop(operator, interceptable=True): # noqa: B902
|
||||
@optimizeconst
|
||||
def visitor(self, node, frame):
|
||||
if (
|
||||
|
||||
@ -160,7 +160,7 @@ def fake_traceback(exc_value, tb, filename, lineno):
|
||||
# the new traceback without this frame.
|
||||
try:
|
||||
exec(code, globals, locals)
|
||||
except:
|
||||
except BaseException:
|
||||
return sys.exc_info()[2].tb_next
|
||||
|
||||
|
||||
|
||||
@ -9,6 +9,8 @@
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
from ._compat import range_type
|
||||
from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401
|
||||
from .tests import TESTS as DEFAULT_TESTS # noqa: F401
|
||||
from .utils import Cycler
|
||||
from .utils import generate_lorem_ipsum
|
||||
from .utils import Joiner
|
||||
@ -29,8 +31,6 @@ 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,
|
||||
|
||||
@ -16,8 +16,6 @@ from functools import reduce
|
||||
|
||||
from . import nodes
|
||||
from ._compat import encode_filename
|
||||
from ._compat import ifilter
|
||||
from ._compat import imap
|
||||
from ._compat import implements_iterator
|
||||
from ._compat import implements_to_string
|
||||
from ._compat import iteritems
|
||||
@ -368,7 +366,8 @@ class Environment(object):
|
||||
self.enable_async = enable_async
|
||||
self.is_async = self.enable_async and have_async_gen
|
||||
if self.is_async:
|
||||
import jinja2.asyncsupport # runs patch_all() once
|
||||
# runs patch_all() to enable async support
|
||||
import jinja2.asyncsupport # noqa: F401
|
||||
|
||||
_environment_sanity_check(self)
|
||||
|
||||
@ -722,7 +721,9 @@ class Environment(object):
|
||||
from jinja2.loaders import ModuleLoader
|
||||
|
||||
if log_function is None:
|
||||
log_function = lambda x: None
|
||||
|
||||
def log_function(x):
|
||||
pass
|
||||
|
||||
if py_compile:
|
||||
if not PY2 or PYPY:
|
||||
@ -806,16 +807,21 @@ class Environment(object):
|
||||
|
||||
.. versionadded:: 2.4
|
||||
"""
|
||||
x = self.loader.list_templates()
|
||||
names = 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
|
||||
|
||||
def filter_func(x):
|
||||
return "." in x and x.rsplit(".", 1)[1] in extensions
|
||||
|
||||
if filter_func is not None:
|
||||
x = list(ifilter(filter_func, x))
|
||||
return x
|
||||
names = [name for name in names if filter_func(name)]
|
||||
|
||||
return names
|
||||
|
||||
def handle_exception(self, source=None):
|
||||
"""Exception handling helper. This is used internally to either raise
|
||||
@ -1202,7 +1208,7 @@ 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(map(int, x.split("="))) for x in self._debug_info.split("&")]
|
||||
return []
|
||||
|
||||
def __repr__(self):
|
||||
|
||||
@ -48,12 +48,14 @@ from .utils import Markup
|
||||
# non unicode strings.
|
||||
GETTEXT_FUNCTIONS = ("_", "gettext", "ngettext")
|
||||
|
||||
_ws_re = re.compile(r"\s*\n\s*")
|
||||
|
||||
|
||||
class ExtensionRegistry(type):
|
||||
"""Gives the extension an unique identifier."""
|
||||
|
||||
def __new__(cls, name, bases, d):
|
||||
rv = type.__new__(cls, name, bases, d)
|
||||
def __new__(mcs, name, bases, d):
|
||||
rv = type.__new__(mcs, name, bases, d)
|
||||
rv.identifier = rv.__module__ + "." + rv.__name__
|
||||
return rv
|
||||
|
||||
@ -356,7 +358,7 @@ class InternationalizationExtension(Extension):
|
||||
else:
|
||||
return node
|
||||
|
||||
def _trim_whitespace(self, string, _ws_re=re.compile(r"\s*\n\s*")):
|
||||
def _trim_whitespace(self, string, _ws_re=_ws_re):
|
||||
return _ws_re.sub(" ", string.strip())
|
||||
|
||||
def _parse_block(self, parser, allow_pluralize):
|
||||
@ -389,7 +391,7 @@ class InternationalizationExtension(Extension):
|
||||
elif parser.stream.eos:
|
||||
parser.fail("unclosed translation block")
|
||||
else:
|
||||
assert False, "internal parser error"
|
||||
raise RuntimeError("internal parser error")
|
||||
|
||||
return referenced, concat(buf)
|
||||
|
||||
@ -574,7 +576,7 @@ def extract_from_ast(node, gettext_functions=GETTEXT_FUNCTIONS, babel_style=True
|
||||
else:
|
||||
strings.append(None)
|
||||
|
||||
for arg in node.kwargs:
|
||||
for _ in node.kwargs:
|
||||
strings.append(None)
|
||||
if node.dyn_args is not None:
|
||||
strings.append(None)
|
||||
@ -699,7 +701,7 @@ def babel_extract(fileobj, keywords, comment_tags, options):
|
||||
try:
|
||||
node = environment.parse(source)
|
||||
tokens = list(environment.lex(environment.preprocess(source)))
|
||||
except TemplateSyntaxError as e:
|
||||
except TemplateSyntaxError:
|
||||
if not silent:
|
||||
raise
|
||||
# skip templates with syntax errors
|
||||
|
||||
@ -328,7 +328,8 @@ def do_sort(environment, value, reverse=False, case_sensitive=False, attribute=N
|
||||
|
||||
.. sourcecode:: jinja
|
||||
|
||||
{% for user in users|sort(attribute="name")|sort(reverse=true, attribute="age") %}
|
||||
{% for user in users|sort(attribute="name")
|
||||
|sort(reverse=true, attribute="age") %}
|
||||
...
|
||||
{% endfor %}
|
||||
|
||||
@ -523,7 +524,8 @@ def do_last(environment, seq):
|
||||
"""
|
||||
Return the last item of a sequence.
|
||||
|
||||
Note: Does not work with generators. You may want to explicitly convert it to a list:
|
||||
Note: Does not work with generators. You may want to explicitly
|
||||
convert it to a list:
|
||||
|
||||
.. sourcecode:: jinja
|
||||
|
||||
@ -931,7 +933,7 @@ def do_round(value, precision=0, method="common"):
|
||||
{{ 42.55|round|int }}
|
||||
-> 43
|
||||
"""
|
||||
if not method in ("common", "ceil", "floor"):
|
||||
if method not in {"common", "ceil", "floor"}:
|
||||
raise FilterArgumentError("method must be common, ceil or floor")
|
||||
if method == "common":
|
||||
return round(value, precision)
|
||||
@ -1282,9 +1284,11 @@ def prepare_map(args, kwargs):
|
||||
args = args[3:]
|
||||
except LookupError:
|
||||
raise FilterArgumentError("map requires a filter argument")
|
||||
func = lambda item: context.environment.call_filter(
|
||||
name, item, args, kwargs, context=context
|
||||
)
|
||||
|
||||
def func(item):
|
||||
return context.environment.call_filter(
|
||||
name, item, args, kwargs, context=context
|
||||
)
|
||||
|
||||
return seq, func
|
||||
|
||||
@ -1301,12 +1305,17 @@ def prepare_select_or_reject(args, kwargs, modfunc, lookup_attr):
|
||||
off = 1
|
||||
else:
|
||||
off = 0
|
||||
transfunc = lambda x: x
|
||||
|
||||
def transfunc(x):
|
||||
return x
|
||||
|
||||
try:
|
||||
name = args[2 + off]
|
||||
args = args[3 + off :]
|
||||
func = lambda item: context.environment.call_test(name, item, args, kwargs)
|
||||
|
||||
def func(item):
|
||||
return context.environment.call_test(name, item, args, kwargs)
|
||||
|
||||
except LookupError:
|
||||
func = bool
|
||||
|
||||
|
||||
@ -379,7 +379,7 @@ class TokenStream(object):
|
||||
|
||||
def skip(self, n=1):
|
||||
"""Got n tokens ahead."""
|
||||
for x in range(n):
|
||||
for _ in range(n):
|
||||
next(self)
|
||||
|
||||
def next_if(self, expr):
|
||||
@ -485,9 +485,11 @@ class Lexer(object):
|
||||
|
||||
def __init__(self, environment):
|
||||
# shortcuts
|
||||
c = lambda x: re.compile(x, re.M | re.S)
|
||||
e = re.escape
|
||||
|
||||
def c(x):
|
||||
return re.compile(x, re.M | re.S)
|
||||
|
||||
# lexing rules for tags
|
||||
tag_rules = [
|
||||
(whitespace_re, TOKEN_WHITESPACE, None),
|
||||
|
||||
@ -208,7 +208,7 @@ class FileSystemLoader(BaseLoader):
|
||||
found = set()
|
||||
for searchpath in self.searchpath:
|
||||
walk_dir = os.walk(searchpath, followlinks=self.followlinks)
|
||||
for dirpath, dirnames, filenames in walk_dir:
|
||||
for dirpath, _, filenames in walk_dir:
|
||||
for filename in filenames:
|
||||
template = (
|
||||
os.path.join(dirpath, filename)[len(searchpath) :]
|
||||
|
||||
@ -54,7 +54,7 @@ class NodeType(type):
|
||||
inheritance. fields and attributes from the parent class are
|
||||
automatically forwarded to the child."""
|
||||
|
||||
def __new__(cls, name, bases, d):
|
||||
def __new__(mcs, name, bases, d):
|
||||
for attr in "fields", "attributes":
|
||||
storage = []
|
||||
storage.extend(getattr(bases[0], attr, ()))
|
||||
@ -63,7 +63,7 @@ class NodeType(type):
|
||||
assert len(storage) == len(set(storage)), "layout conflict"
|
||||
d[attr] = tuple(storage)
|
||||
d.setdefault("abstract", False)
|
||||
return type.__new__(cls, name, bases, d)
|
||||
return type.__new__(mcs, name, bases, d)
|
||||
|
||||
|
||||
class EvalContext(object):
|
||||
@ -165,7 +165,7 @@ class Node(with_metaclass(NodeType, object)):
|
||||
over all fields and yields the values of they are nodes. If the value
|
||||
of a field is a list all the nodes in that list are returned.
|
||||
"""
|
||||
for field, item in self.iter_fields(exclude, only):
|
||||
for _, item in self.iter_fields(exclude, only):
|
||||
if isinstance(item, list):
|
||||
for n in item:
|
||||
if isinstance(n, Node):
|
||||
|
||||
@ -245,7 +245,6 @@ class Parser(object):
|
||||
targets = []
|
||||
values = []
|
||||
while self.stream.current.type != "block_end":
|
||||
lineno = self.stream.current.lineno
|
||||
if targets:
|
||||
self.stream.expect("comma")
|
||||
target = self.parse_assign_target()
|
||||
@ -639,7 +638,10 @@ class Parser(object):
|
||||
elif with_condexpr:
|
||||
parse = self.parse_expression
|
||||
else:
|
||||
parse = lambda: self.parse_expression(with_condexpr=False)
|
||||
|
||||
def parse():
|
||||
return self.parse_expression(with_condexpr=False)
|
||||
|
||||
args = []
|
||||
is_tuple = False
|
||||
while 1:
|
||||
|
||||
@ -12,6 +12,10 @@ import sys
|
||||
from itertools import chain
|
||||
from types import MethodType
|
||||
|
||||
from markupsafe import escape
|
||||
from markupsafe import Markup
|
||||
from markupsafe import soft_unicode
|
||||
|
||||
from ._compat import abc
|
||||
from ._compat import imap
|
||||
from ._compat import implements_iterator
|
||||
@ -26,14 +30,11 @@ from .exceptions import TemplateRuntimeError
|
||||
from .exceptions import UndefinedError
|
||||
from .nodes import EvalContext
|
||||
from .utils import concat
|
||||
from .utils import escape
|
||||
from .utils import evalcontextfunction
|
||||
from .utils import internalcode
|
||||
from .utils import Markup
|
||||
from .utils import missing
|
||||
from .utils import Namespace
|
||||
from .utils import object_type_repr
|
||||
from .utils import soft_unicode
|
||||
|
||||
# these variables are exported to the template runtime
|
||||
__all__ = [
|
||||
@ -58,11 +59,12 @@ __all__ = [
|
||||
#: a string. We can just use the text type here.
|
||||
to_string = text_type
|
||||
|
||||
#: the identity function. Useful for certain things in the environment
|
||||
identity = lambda x: x
|
||||
|
||||
_first_iteration = object()
|
||||
_last_iteration = object()
|
||||
def identity(x):
|
||||
"""Returns its argument. Useful for certain things in the
|
||||
environment.
|
||||
"""
|
||||
return x
|
||||
|
||||
|
||||
def markup_join(seq):
|
||||
@ -127,8 +129,8 @@ def _get_func(x):
|
||||
|
||||
|
||||
class ContextMeta(type):
|
||||
def __new__(cls, name, bases, d):
|
||||
rv = type.__new__(cls, name, bases, d)
|
||||
def __new__(mcs, name, bases, d):
|
||||
rv = type.__new__(mcs, name, bases, d)
|
||||
if bases == ():
|
||||
return rv
|
||||
|
||||
@ -264,7 +266,7 @@ class Context(with_metaclass(ContextMeta)):
|
||||
return dict(self.parent, **self.vars)
|
||||
|
||||
@internalcode
|
||||
def call(__self, __obj, *args, **kwargs):
|
||||
def call(__self, __obj, *args, **kwargs): # noqa: B902
|
||||
"""Call the callable with the arguments and keyword arguments
|
||||
provided but inject the active context or environment as first
|
||||
argument if the callable is a :func:`contextfunction` or
|
||||
@ -274,7 +276,7 @@ class Context(with_metaclass(ContextMeta)):
|
||||
__traceback_hide__ = True # noqa
|
||||
|
||||
# Allow callable classes to take a context
|
||||
if hasattr(__obj, "__call__"):
|
||||
if hasattr(__obj, "__call__"): # noqa: B004
|
||||
fn = __obj.__call__
|
||||
for fn_type in (
|
||||
"contextfunction",
|
||||
@ -313,8 +315,10 @@ class Context(with_metaclass(ContextMeta)):
|
||||
context.blocks.update((k, list(v)) for k, v in iteritems(self.blocks))
|
||||
return context
|
||||
|
||||
def _all(meth):
|
||||
proxy = lambda self: getattr(self.get_all(), meth)()
|
||||
def _all(meth): # noqa: B902
|
||||
def proxy(self):
|
||||
return getattr(self.get_all(), meth)()
|
||||
|
||||
proxy.__doc__ = getattr(dict, meth).__doc__
|
||||
proxy.__name__ = meth
|
||||
return proxy
|
||||
@ -635,7 +639,7 @@ 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 name in self.arguments[len(arguments) :]:
|
||||
try:
|
||||
value = kwargs.pop(name)
|
||||
except KeyError:
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
"""
|
||||
import operator
|
||||
import types
|
||||
import warnings
|
||||
from collections import deque
|
||||
from string import Formatter
|
||||
|
||||
from markupsafe import EscapeFormatter
|
||||
@ -31,36 +33,35 @@ 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 = {
|
||||
"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.
|
||||
UNSAFE_FUNCTION_ATTRIBUTES = set()
|
||||
|
||||
|
||||
#: unsafe method attributes. function attributes are unsafe for methods too
|
||||
UNSAFE_METHOD_ATTRIBUTES = set(["im_class", "im_func", "im_self"])
|
||||
UNSAFE_METHOD_ATTRIBUTES = {"im_class", "im_func", "im_self"}
|
||||
|
||||
#: unsafe generator attributes.
|
||||
UNSAFE_GENERATOR_ATTRIBUTES = set(["gi_frame", "gi_code"])
|
||||
UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}
|
||||
|
||||
#: unsafe attributes on coroutines
|
||||
UNSAFE_COROUTINE_ATTRIBUTES = set(["cr_frame", "cr_code"])
|
||||
UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"}
|
||||
|
||||
#: unsafe attributes on async generators
|
||||
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set(["ag_code", "ag_frame"])
|
||||
|
||||
import warnings
|
||||
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"}
|
||||
|
||||
# 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"
|
||||
)
|
||||
|
||||
from collections import deque
|
||||
|
||||
_mutable_set_types = (set,)
|
||||
_mutable_mapping_types = (dict,)
|
||||
_mutable_sequence_types = (list,)
|
||||
@ -89,7 +90,6 @@ _mutable_set_types += (abc.MutableSet,)
|
||||
_mutable_mapping_types += (abc.MutableMapping,)
|
||||
_mutable_sequence_types += (abc.MutableSequence,)
|
||||
|
||||
|
||||
_mutable_spec = (
|
||||
(
|
||||
_mutable_set_types,
|
||||
@ -460,7 +460,7 @@ class SandboxedEnvironment(Environment):
|
||||
rv = formatter.vformat(s, args, kwargs)
|
||||
return type(s)(rv)
|
||||
|
||||
def call(__self, __context, __obj, *args, **kwargs):
|
||||
def call(__self, __context, __obj, *args, **kwargs): # noqa: B902
|
||||
"""Call an object from sandboxed code."""
|
||||
fmt = inspect_format_method(__obj)
|
||||
if fmt is not None:
|
||||
|
||||
@ -142,7 +142,7 @@ def test_sequence(value):
|
||||
try:
|
||||
len(value)
|
||||
value.__getitem__
|
||||
except:
|
||||
except Exception:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@ -15,6 +15,9 @@ import warnings
|
||||
from collections import deque
|
||||
from threading import Lock
|
||||
|
||||
from markupsafe import escape
|
||||
from markupsafe import Markup
|
||||
|
||||
from ._compat import abc
|
||||
from ._compat import string_types
|
||||
from ._compat import text_type
|
||||
@ -109,7 +112,7 @@ def is_undefined(obj):
|
||||
|
||||
def consume(iterable):
|
||||
"""Consumes an iterable without doing anything with it."""
|
||||
for event in iterable:
|
||||
for _ in iterable:
|
||||
pass
|
||||
|
||||
|
||||
@ -246,7 +249,7 @@ def urlize(text, trim_url_limit=None, rel=None, target=None):
|
||||
if (
|
||||
"@" in middle
|
||||
and not middle.startswith("www.")
|
||||
and not ":" in middle
|
||||
and ":" not in middle
|
||||
and _simple_email_re.match(middle)
|
||||
):
|
||||
middle = '<a href="mailto:%s">%s</a>' % (middle, middle)
|
||||
@ -472,6 +475,12 @@ class LRUCache(object):
|
||||
|
||||
def iteritems(self):
|
||||
"""Iterate over all items."""
|
||||
warnings.warn(
|
||||
"'iteritems()' will be removed in version 3.0. Use"
|
||||
" 'iter(cache.items())' instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return iter(self.items())
|
||||
|
||||
def values(self):
|
||||
@ -481,16 +490,21 @@ 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.'
|
||||
),
|
||||
"'itervalue()' will be removed in version 3.0. Use"
|
||||
" 'iter(cache.values())' instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return self.itervalues()
|
||||
return iter(self.values())
|
||||
|
||||
def itervalues(self):
|
||||
"""Iterate over all values."""
|
||||
warnings.warn(
|
||||
"'itervalues()' will be removed in version 3.0. Use"
|
||||
" 'iter(cache.values())' instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return iter(self.values())
|
||||
|
||||
def keys(self):
|
||||
@ -501,9 +515,16 @@ class LRUCache(object):
|
||||
"""Iterate over all keys in the cache dict, ordered by
|
||||
the most recent usage.
|
||||
"""
|
||||
return reversed(tuple(self._queue))
|
||||
warnings.warn(
|
||||
"'iterkeys()' will be removed in version 3.0. Use"
|
||||
" 'iter(cache.keys())' instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return iter(self)
|
||||
|
||||
__iter__ = iterkeys
|
||||
def __iter__(self):
|
||||
return reversed(tuple(self._queue))
|
||||
|
||||
def __reversed__(self):
|
||||
"""Iterate over the keys in the cache dict, oldest items
|
||||
@ -675,7 +696,7 @@ class Namespace(object):
|
||||
"""A namespace object that can hold arbitrary attributes. It may be
|
||||
initialized from a dictionary or with keyword arguments."""
|
||||
|
||||
def __init__(*args, **kwargs):
|
||||
def __init__(*args, **kwargs): # noqa: B902
|
||||
self, args = args[0], args[1:]
|
||||
self.__attrs = dict(*args, **kwargs)
|
||||
|
||||
@ -702,5 +723,13 @@ except SyntaxError:
|
||||
have_async_gen = False
|
||||
|
||||
|
||||
# Imported here because that's where it was in the past
|
||||
from markupsafe import Markup, escape, soft_unicode
|
||||
def soft_unicode(s):
|
||||
from markupsafe import soft_unicode
|
||||
|
||||
warnings.warn(
|
||||
"'jinja2.utils.soft_unicode' will be removed in version 3.0."
|
||||
" Use 'markupsafe.soft_unicode' instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
return soft_unicode(s)
|
||||
|
||||
@ -105,17 +105,6 @@ class TestExtendedAPI(object):
|
||||
c.reset()
|
||||
assert c.current == 1
|
||||
|
||||
def test_cycler_nextmethod(self, env):
|
||||
items = 1, 2, 3
|
||||
c = Cycler(*items)
|
||||
for item in items + items:
|
||||
assert c.current == item
|
||||
assert c.next() == item
|
||||
c.next()
|
||||
assert c.current == 2
|
||||
c.reset()
|
||||
assert c.current == 1
|
||||
|
||||
def test_expressions(self, env):
|
||||
expr = env.compile_expression("foo")
|
||||
assert expr() is None
|
||||
@ -338,7 +327,7 @@ class TestUndefined(object):
|
||||
assert und1 != 42
|
||||
assert hash(und1) == hash(und2) == hash(Undefined())
|
||||
with pytest.raises(AttributeError):
|
||||
getattr(Undefined, "__slots__")
|
||||
getattr(Undefined, "__slots__") # noqa: B009
|
||||
|
||||
def test_chainable_undefined(self):
|
||||
env = Environment(undefined=ChainableUndefined)
|
||||
@ -350,7 +339,7 @@ class TestUndefined(object):
|
||||
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__") # noqa: B009
|
||||
|
||||
# The following tests ensure subclass functionality works as expected
|
||||
assert env.from_string('{{ missing.bar["baz"] }}').render() == u""
|
||||
@ -385,7 +374,7 @@ class TestUndefined(object):
|
||||
== u"{{ undefined value printed: %s }}" % undefined_hint
|
||||
)
|
||||
with pytest.raises(AttributeError):
|
||||
getattr(DebugUndefined, "__slots__")
|
||||
getattr(DebugUndefined, "__slots__") # noqa: B009
|
||||
|
||||
def test_strict_undefined(self):
|
||||
env = Environment(undefined=StrictUndefined)
|
||||
@ -402,7 +391,7 @@ class TestUndefined(object):
|
||||
== "default"
|
||||
)
|
||||
with pytest.raises(AttributeError):
|
||||
getattr(StrictUndefined, "__slots__")
|
||||
getattr(StrictUndefined, "__slots__") # noqa: B009
|
||||
assert env.from_string('{{ "foo" if false }}').render() == ""
|
||||
|
||||
def test_indexing_gives_undefined(self):
|
||||
|
||||
@ -396,9 +396,8 @@ class TestAsyncForLoop(object):
|
||||
|
||||
def test_recursive_depth0(self, test_env_async):
|
||||
tmpl = test_env_async.from_string(
|
||||
"""{% for item in seq recursive -%}
|
||||
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
{%- endfor %}"""
|
||||
"{% for item in seq recursive %}[{{ loop.depth0 }}:{{ item.a }}"
|
||||
"{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
|
||||
)
|
||||
assert (
|
||||
tmpl.render(
|
||||
@ -413,9 +412,8 @@ class TestAsyncForLoop(object):
|
||||
|
||||
def test_recursive_depth(self, test_env_async):
|
||||
tmpl = test_env_async.from_string(
|
||||
"""{% for item in seq recursive -%}
|
||||
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
{%- endfor %}"""
|
||||
"{% for item in seq recursive %}[{{ loop.depth }}:{{ item.a }}"
|
||||
"{% if item.b %}<{{ loop(item.b) }}>{% endif %}]{% endfor %}"
|
||||
)
|
||||
assert (
|
||||
tmpl.render(
|
||||
@ -544,9 +542,7 @@ class TestAsyncForLoop(object):
|
||||
)
|
||||
sm = t.render(
|
||||
this="/foo",
|
||||
site={
|
||||
"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"},]}
|
||||
},
|
||||
site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
|
||||
)
|
||||
lines = [x.strip() for x in sm.splitlines() if x.strip()]
|
||||
assert lines == [
|
||||
@ -569,7 +565,7 @@ class TestAsyncForLoop(object):
|
||||
"""
|
||||
)
|
||||
sm = t.render(
|
||||
this="/foo", items=[{"url": "/"}, {"url": "/foo"}, {"url": "/bar"},]
|
||||
this="/foo", items=[{"url": "/"}, {"url": "/foo"}, {"url": "/bar"}]
|
||||
)
|
||||
lines = [x.strip() for x in sm.splitlines() if x.strip()]
|
||||
assert lines == [
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
|
||||
from jinja2 import Environment
|
||||
@ -12,7 +14,7 @@ async def make_aiter(iter):
|
||||
def mark_dualiter(parameter, factory):
|
||||
def decorator(f):
|
||||
return pytest.mark.parametrize(
|
||||
parameter, [lambda: factory(), lambda: make_aiter(factory()),]
|
||||
parameter, [lambda: factory(), lambda: make_aiter(factory())]
|
||||
)(f)
|
||||
|
||||
return decorator
|
||||
@ -66,22 +68,13 @@ def test_groupby_tuple_index(env_async, items):
|
||||
|
||||
|
||||
def make_articles():
|
||||
class Date(object):
|
||||
def __init__(self, day, month, year):
|
||||
self.day = day
|
||||
self.month = month
|
||||
self.year = year
|
||||
|
||||
class Article(object):
|
||||
def __init__(self, title, *date):
|
||||
self.date = Date(*date)
|
||||
self.title = title
|
||||
|
||||
Date = namedtuple("Date", "day,month,year")
|
||||
Article = namedtuple("Article", "title,date")
|
||||
return [
|
||||
Article("aha", 1, 1, 1970),
|
||||
Article("interesting", 2, 1, 1970),
|
||||
Article("really?", 3, 1, 1970),
|
||||
Article("totally not", 1, 1, 1971),
|
||||
Article("aha", Date(1, 1, 1970)),
|
||||
Article("interesting", Date(2, 1, 1970)),
|
||||
Article("really?", Date(3, 1, 1970)),
|
||||
Article("totally not", Date(1, 1, 1971)),
|
||||
]
|
||||
|
||||
|
||||
@ -115,10 +108,7 @@ def test_join_string_list(string_items):
|
||||
|
||||
|
||||
def make_users():
|
||||
class User(object):
|
||||
def __init__(self, username):
|
||||
self.username = username
|
||||
|
||||
User = namedtuple("User", "username")
|
||||
return map(User, ["foo", "bar"])
|
||||
|
||||
|
||||
@ -153,11 +143,7 @@ def test_bool_select(env_async, items):
|
||||
|
||||
|
||||
def make_users():
|
||||
class User(object):
|
||||
def __init__(self, name, is_active):
|
||||
self.name = name
|
||||
self.is_active = is_active
|
||||
|
||||
User = namedtuple("User", "name,is_active")
|
||||
return [
|
||||
User("john", True),
|
||||
User("jane", True),
|
||||
@ -201,7 +187,7 @@ def test_sum(env_async, items):
|
||||
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') }}""")
|
||||
assert tmpl.render(items=items)
|
||||
@ -223,13 +209,13 @@ def test_sum_attributes_nested(env_async):
|
||||
|
||||
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"
|
||||
assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18}) == "42"
|
||||
|
||||
|
||||
@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 }}'
|
||||
"{{ items()|slice(3)|list }}|{{ items()|slice(3, 'X')|list }}"
|
||||
)
|
||||
out = tmpl.render(items=items)
|
||||
assert out == (
|
||||
|
||||
@ -163,7 +163,7 @@ class TestForLoop(object):
|
||||
def test_recursive_depth0(self, env):
|
||||
tmpl = env.from_string(
|
||||
"""{% for item in seq recursive -%}
|
||||
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
[{{ loop.depth0 }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
{%- endfor %}"""
|
||||
)
|
||||
assert (
|
||||
@ -180,7 +180,7 @@ class TestForLoop(object):
|
||||
def test_recursive_depth(self, env):
|
||||
tmpl = env.from_string(
|
||||
"""{% for item in seq recursive -%}
|
||||
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
[{{ loop.depth }}:{{ item.a }}{% if item.b %}<{{ loop(item.b) }}>{% endif %}]
|
||||
{%- endfor %}"""
|
||||
)
|
||||
assert (
|
||||
@ -513,15 +513,13 @@ class TestSet(object):
|
||||
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" %}'
|
||||
)
|
||||
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 }}"
|
||||
"{% set ns = namespace() %}{% set ns.bar = '42' %}{{ ns.bar }}"
|
||||
)
|
||||
assert tmpl.render() == "42"
|
||||
|
||||
|
||||
@ -10,7 +10,6 @@
|
||||
"""
|
||||
import pickle
|
||||
import re
|
||||
import sys
|
||||
from traceback import format_exception
|
||||
|
||||
import pytest
|
||||
@ -30,17 +29,15 @@ def fs_env(filesystem_loader):
|
||||
@pytest.mark.debug
|
||||
class TestDebug(object):
|
||||
def assert_traceback_matches(self, callback, expected_tb):
|
||||
try:
|
||||
with pytest.raises(Exception) as exc_info:
|
||||
callback()
|
||||
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,
|
||||
)
|
||||
else:
|
||||
assert False, "Expected exception"
|
||||
|
||||
tb = format_exception(exc_info.type, exc_info.value, exc_info.tb)
|
||||
m = re.search(expected_tb.strip(), "".join(tb))
|
||||
assert m is not None, "Traceback did not match:\n\n%s\nexpected:\n%s" % (
|
||||
"".join(tb),
|
||||
expected_tb,
|
||||
)
|
||||
|
||||
def test_runtime_error(self, fs_env):
|
||||
def test():
|
||||
@ -64,10 +61,12 @@ ZeroDivisionError: (int(eger)? )?division (or modulo )?by zero
|
||||
# error in the middle of other compiler frames.
|
||||
self.assert_traceback_matches(
|
||||
lambda: fs_env.get_template("syntaxerror.html"),
|
||||
r"""(?sm)
|
||||
"""(?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'.
|
||||
\\{% 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'.
|
||||
""",
|
||||
)
|
||||
|
||||
|
||||
@ -343,7 +343,7 @@ class TestInternationalization(object):
|
||||
# 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 -%}"
|
||||
"{%- trans trimmed = 'world' %} hello\n {{ trimmed }} {% endtrans -%}"
|
||||
)
|
||||
assert tmpl.render() == " hello\n world "
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ import pytest
|
||||
from jinja2 import contextfilter
|
||||
from jinja2 import Environment
|
||||
from jinja2 import Template
|
||||
from jinja2._compat import text_type
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info < (3, 5), reason="Requires 3.5 or later")
|
||||
@ -29,7 +30,7 @@ def test_ascii_str():
|
||||
|
||||
env.policies["compiler.ascii_str"] = False
|
||||
t = env.from_string('{{ "foo"|assert }}')
|
||||
t.render(expected_type=unicode)
|
||||
t.render(expected_type=text_type)
|
||||
|
||||
env.policies["compiler.ascii_str"] = True
|
||||
t = env.from_string('{{ "foo"|assert }}')
|
||||
@ -38,4 +39,4 @@ def test_ascii_str():
|
||||
for val in True, False:
|
||||
env.policies["compiler.ascii_str"] = val
|
||||
t = env.from_string(u'{{ "\N{SNOWMAN}"|assert }}')
|
||||
t.render(expected_type=unicode)
|
||||
t.render(expected_type=text_type)
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
:license: BSD, see LICENSE for more details.
|
||||
"""
|
||||
import random
|
||||
from collections import namedtuple
|
||||
|
||||
import pytest
|
||||
|
||||
@ -81,9 +82,7 @@ class TestFilter(object):
|
||||
)
|
||||
|
||||
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]]|"
|
||||
@ -244,10 +243,7 @@ class TestFilter(object):
|
||||
assert tmpl.render() == "<foo><span>foo</span>"
|
||||
|
||||
def test_join_attribute(self, env):
|
||||
class User(object):
|
||||
def __init__(self, username):
|
||||
self.username = username
|
||||
|
||||
User = namedtuple("User", "username")
|
||||
tmpl = env.from_string("""{{ users|join(', ', 'username') }}""")
|
||||
assert tmpl.render(users=map(User, ["foo", "bar"])) == "foo, bar"
|
||||
|
||||
@ -291,7 +287,7 @@ class TestFilter(object):
|
||||
|
||||
def test_reverse(self, env):
|
||||
tmpl = env.from_string(
|
||||
'{{ "foobar"|reverse|join }}|' "{{ [1, 2, 3]|reverse|list }}"
|
||||
"{{ 'foobar'|reverse|join }}|{{ [1, 2, 3]|reverse|list }}"
|
||||
)
|
||||
assert tmpl.render() == "raboof|[3, 2, 1]"
|
||||
|
||||
@ -370,7 +366,7 @@ class TestFilter(object):
|
||||
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):
|
||||
@ -401,7 +397,7 @@ class TestFilter(object):
|
||||
|
||||
def test_sum_attributes(self, env):
|
||||
tmpl = env.from_string("""{{ values|sum('value') }}""")
|
||||
assert tmpl.render(values=[{"value": 23}, {"value": 1}, {"value": 18},]) == "42"
|
||||
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') }}""")
|
||||
@ -418,7 +414,7 @@ class TestFilter(object):
|
||||
|
||||
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"
|
||||
assert tmpl.render(values={"foo": 23, "bar": 1, "baz": 18}) == "42"
|
||||
|
||||
def test_abs(self, env):
|
||||
tmpl = env.from_string("""{{ -1|abs }}|{{ 1|abs }}""")
|
||||
@ -561,22 +557,13 @@ class TestFilter(object):
|
||||
assert tmpl.render() == "a:1:2|b:1|"
|
||||
|
||||
def test_groupby_multidot(self, env):
|
||||
class Date(object):
|
||||
def __init__(self, day, month, year):
|
||||
self.day = day
|
||||
self.month = month
|
||||
self.year = year
|
||||
|
||||
class Article(object):
|
||||
def __init__(self, title, *date):
|
||||
self.date = Date(*date)
|
||||
self.title = title
|
||||
|
||||
Date = namedtuple("Date", "day,month,year")
|
||||
Article = namedtuple("Article", "title,date")
|
||||
articles = [
|
||||
Article("aha", 1, 1, 1970),
|
||||
Article("interesting", 2, 1, 1970),
|
||||
Article("really?", 3, 1, 1970),
|
||||
Article("totally not", 1, 1, 1971),
|
||||
Article("aha", Date(1, 1, 1970)),
|
||||
Article("interesting", Date(2, 1, 1970)),
|
||||
Article("really?", Date(3, 1, 1970)),
|
||||
Article("totally not", Date(1, 1, 1971)),
|
||||
]
|
||||
tmpl = env.from_string(
|
||||
"""
|
||||
@ -647,10 +634,7 @@ class TestFilter(object):
|
||||
assert tmpl.render() == "[3, 3, 15]"
|
||||
|
||||
def test_attribute_map(self, env):
|
||||
class User(object):
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
||||
User = namedtuple("User", "name")
|
||||
env = Environment()
|
||||
users = [
|
||||
User("john"),
|
||||
@ -666,15 +650,8 @@ class TestFilter(object):
|
||||
assert tmpl.render() == "[]"
|
||||
|
||||
def test_map_default(self, env):
|
||||
class Fullname(object):
|
||||
def __init__(self, firstname, lastname):
|
||||
self.firstname = firstname
|
||||
self.lastname = lastname
|
||||
|
||||
class Firstname(object):
|
||||
def __init__(self, firstname):
|
||||
self.firstname = firstname
|
||||
|
||||
Fullname = namedtuple("Fullname", "firstname,lastname")
|
||||
Firstname = namedtuple("Firstname", "firstname")
|
||||
env = Environment()
|
||||
tmpl = env.from_string(
|
||||
'{{ users|map(attribute="lastname", default="smith")|join(", ") }}'
|
||||
@ -708,11 +685,7 @@ class TestFilter(object):
|
||||
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
|
||||
|
||||
User = namedtuple("User", "name,is_active")
|
||||
env = Environment()
|
||||
users = [
|
||||
User("john", True),
|
||||
@ -725,11 +698,7 @@ class TestFilter(object):
|
||||
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
|
||||
|
||||
User = namedtuple("User", "name,is_active")
|
||||
env = Environment()
|
||||
users = [
|
||||
User("john", True),
|
||||
@ -742,11 +711,7 @@ class TestFilter(object):
|
||||
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
|
||||
|
||||
User = namedtuple("User", "id,name")
|
||||
env = Environment()
|
||||
users = [
|
||||
User(1, "john"),
|
||||
@ -759,11 +724,7 @@ class TestFilter(object):
|
||||
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
|
||||
|
||||
User = namedtuple("User", "id,name")
|
||||
env = Environment()
|
||||
users = [
|
||||
User(1, "john"),
|
||||
|
||||
@ -180,9 +180,9 @@ class TestIncludes(object):
|
||||
|
||||
def test_import_from_with_context(self):
|
||||
env = Environment(
|
||||
loader=DictLoader({"a": "{% macro x() %}{{ foobar }}{% endmacro %}",})
|
||||
loader=DictLoader({"a": "{% macro x() %}{{ foobar }}{% endmacro %}"})
|
||||
)
|
||||
t = env.from_string(
|
||||
'{% set foobar = 42 %}{% from "a" ' "import x with context %}{{ x() }}"
|
||||
"{% set foobar = 42 %}{% from 'a' import x with context %}{{ x() }}"
|
||||
)
|
||||
assert t.render() == "42"
|
||||
|
||||
@ -12,7 +12,6 @@ import pytest
|
||||
|
||||
from jinja2 import DictLoader
|
||||
from jinja2 import Environment
|
||||
from jinja2 import TemplateError
|
||||
from jinja2 import TemplateRuntimeError
|
||||
|
||||
LAYOUTTEMPLATE = """\
|
||||
@ -135,7 +134,7 @@ class TestInheritance(object):
|
||||
assert tmpl.render() == "--INTRO--|BEFORE|[(INNER)]|AFTER"
|
||||
|
||||
def test_working(self, env):
|
||||
tmpl = env.get_template("working")
|
||||
env.get_template("working")
|
||||
|
||||
def test_reuse_blocks(self, env):
|
||||
tmpl = env.from_string(
|
||||
@ -196,7 +195,7 @@ class TestInheritance(object):
|
||||
)
|
||||
)
|
||||
t = env.from_string(
|
||||
'{% extends "master.html" %}{% block item %}' "{{ item }}{% endblock %}"
|
||||
"{% extends 'master.html' %}{% block item %}{{ item }}{% endblock %}"
|
||||
)
|
||||
assert t.render(seq=list(range(5))) == "[0][1][2][3][4]"
|
||||
|
||||
|
||||
@ -81,13 +81,15 @@ class TestLexer(object):
|
||||
assert tmpl.render() == "123"
|
||||
|
||||
def test_raw3(self, env):
|
||||
# The second newline after baz exists because it is AFTER the {% raw %} and is ignored.
|
||||
# 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"
|
||||
|
||||
def test_raw4(self, env):
|
||||
# The trailing dash of the {% raw -%} cleans both the spaces and newlines up to the first character of data.
|
||||
# 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"
|
||||
@ -531,7 +533,7 @@ class TestSyntax(object):
|
||||
def test_notin(self, env):
|
||||
bar = range(100)
|
||||
tmpl = env.from_string("""{{ not 42 in bar }}""")
|
||||
assert tmpl.render(bar=bar) == text_type(not 42 in bar)
|
||||
assert tmpl.render(bar=bar) == "False"
|
||||
|
||||
def test_operator_precedence(self, env):
|
||||
tmpl = env.from_string("""{{ 2 * 3 + 4 % 2 + 1 - 2 }}""")
|
||||
|
||||
@ -99,7 +99,7 @@ class TestLoaders(object):
|
||||
t2 = env.get_template("two")
|
||||
assert t2 is env.get_template("two")
|
||||
assert t1 is env.get_template("one")
|
||||
t3 = env.get_template("three")
|
||||
env.get_template("three")
|
||||
loader_ref = weakref.ref(loader)
|
||||
assert (loader_ref, "one") in env.cache
|
||||
assert (loader_ref, "two") not in env.cache
|
||||
@ -183,7 +183,10 @@ class TestFileSystemLoader(object):
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("encoding", "expect"),
|
||||
[("utf-8", u"文字化け"), ("iso-8859-1", u"æ\x96\x87å\xad\x97å\x8c\x96ã\x81\x91"),],
|
||||
[
|
||||
("utf-8", u"文字化け"),
|
||||
("iso-8859-1", u"æ\x96\x87\xe5\xad\x97\xe5\x8c\x96\xe3\x81\x91"),
|
||||
],
|
||||
)
|
||||
def test_uses_specified_encoding(self, encoding, expect):
|
||||
loader = loaders.FileSystemLoader(self.searchpath, encoding=encoding)
|
||||
@ -254,7 +257,7 @@ class TestModuleLoader(object):
|
||||
|
||||
def test_weak_references(self, prefix_loader):
|
||||
self.compile_down(prefix_loader)
|
||||
tmpl = self.mod_env.get_template("a/test.html")
|
||||
self.mod_env.get_template("a/test.html")
|
||||
key = loaders.ModuleLoader.get_template_key("a/test.html")
|
||||
name = self.mod_env.loader.module.__name__
|
||||
|
||||
@ -262,13 +265,13 @@ class TestModuleLoader(object):
|
||||
assert name in sys.modules
|
||||
|
||||
# unset all, ensure the module is gone from sys.modules
|
||||
self.mod_env = tmpl = None
|
||||
self.mod_env = None
|
||||
|
||||
try:
|
||||
import gc
|
||||
|
||||
gc.collect()
|
||||
except:
|
||||
except BaseException:
|
||||
pass
|
||||
|
||||
assert name not in sys.modules
|
||||
@ -280,32 +283,28 @@ class TestModuleLoader(object):
|
||||
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")
|
||||
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.compile_down(prefix_loader)
|
||||
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"
|
||||
|
||||
def test_prefix_loader(self, prefix_loader):
|
||||
log = self.compile_down(prefix_loader)
|
||||
|
||||
self.compile_down(prefix_loader)
|
||||
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")
|
||||
|
||||
@ -254,35 +254,34 @@ class TestBug(object):
|
||||
)
|
||||
pytest.raises(TemplateSyntaxError, Template, "{% for x in %}..{% endfor %}")
|
||||
|
||||
def test_recursive_loop_bug(self, env):
|
||||
tpl1 = Template(
|
||||
def test_recursive_loop_compile(self, env):
|
||||
Template(
|
||||
"""
|
||||
{% for p in foo recursive%}
|
||||
{{p.bar}}
|
||||
{% for f in p.fields recursive%}
|
||||
{{f.baz}}
|
||||
{% for p in foo recursive%}
|
||||
{{p.bar}}
|
||||
{% if f.rec %}
|
||||
{{ loop(f.sub) }}
|
||||
{% endif %}
|
||||
{% for f in p.fields recursive%}
|
||||
{{f.baz}}
|
||||
{{p.bar}}
|
||||
{% if f.rec %}
|
||||
{{ loop(f.sub) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
"""
|
||||
"""
|
||||
)
|
||||
|
||||
tpl2 = Template(
|
||||
Template(
|
||||
"""
|
||||
{% for p in foo%}
|
||||
{{p.bar}}
|
||||
{% for f in p.fields recursive%}
|
||||
{{f.baz}}
|
||||
{% for p in foo%}
|
||||
{{p.bar}}
|
||||
{% if f.rec %}
|
||||
{{ loop(f.sub) }}
|
||||
{% endif %}
|
||||
{% for f in p.fields recursive%}
|
||||
{{f.baz}}
|
||||
{{p.bar}}
|
||||
{% if f.rec %}
|
||||
{{ loop(f.sub) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
"""
|
||||
"""
|
||||
)
|
||||
|
||||
def test_else_loop_bug(self, env):
|
||||
@ -327,7 +326,7 @@ class TestBug(object):
|
||||
|
||||
def test_block_set_with_extends(self):
|
||||
env = Environment(
|
||||
loader=DictLoader({"main": "{% block body %}[{{ x }}]{% endblock %}",})
|
||||
loader=DictLoader({"main": "{% block body %}[{{ x }}]{% endblock %}"})
|
||||
)
|
||||
t = env.from_string('{% extends "main" %}{% set x %}42{% endset %}')
|
||||
assert t.render() == "[42]"
|
||||
@ -538,9 +537,7 @@ class TestBug(object):
|
||||
)
|
||||
sm = t.render(
|
||||
this="/foo",
|
||||
site={
|
||||
"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"},]}
|
||||
},
|
||||
site={"root": {"url": "/", "children": [{"url": "/foo"}, {"url": "/bar"}]}},
|
||||
)
|
||||
lines = [x.strip() for x in sm.splitlines() if x.strip()]
|
||||
assert lines == [
|
||||
@ -581,8 +578,8 @@ class TestBug(object):
|
||||
env = Environment(
|
||||
loader=DictLoader(
|
||||
{
|
||||
"inc": "{{ item }}",
|
||||
"main": '{% for item in [1, 2, 3] %}{% include "inc" %}{% endfor %}',
|
||||
"inc": "{{ i }}",
|
||||
"main": '{% for i in [1, 2, 3] %}{% include "inc" %}{% endfor %}',
|
||||
}
|
||||
)
|
||||
)
|
||||
@ -611,7 +608,7 @@ class TestBug(object):
|
||||
assert env.get_template("test").render(foobar="test") == "test"
|
||||
|
||||
def test_legacy_custom_context(self, env):
|
||||
from jinja2.runtime import Context, Undefined, missing
|
||||
from jinja2.runtime import Context, missing
|
||||
|
||||
class MyContext(Context):
|
||||
def resolve(self, name):
|
||||
@ -627,9 +624,7 @@ class TestBug(object):
|
||||
|
||||
def test_recursive_loop_bug(self, env):
|
||||
tmpl = env.from_string(
|
||||
"""
|
||||
{%- for value in values recursive %}1{% else %}0{% endfor -%}
|
||||
"""
|
||||
"{%- for value in values recursive %}1{% else %}0{% endfor -%}"
|
||||
)
|
||||
assert tmpl.render(values=[]) == "0"
|
||||
|
||||
|
||||
@ -3,18 +3,14 @@ import itertools
|
||||
from jinja2 import Template
|
||||
from jinja2.runtime import LoopContext
|
||||
|
||||
|
||||
TEST_IDX_TEMPLATE_STR_1 = (
|
||||
"[{% for i in lst|reverse %}"
|
||||
+ "(len={{ loop.length }}, revindex={{ loop.revindex }}, index={{ loop.index }}, val={{ i }})"
|
||||
+ "{% endfor %}]"
|
||||
"[{% for i in lst|reverse %}(len={{ loop.length }},"
|
||||
" revindex={{ loop.revindex }}, index={{ loop.index }}, val={{ i }}){% endfor %}]"
|
||||
)
|
||||
|
||||
|
||||
TEST_IDX0_TEMPLATE_STR_1 = (
|
||||
"[{% for i in lst|reverse %}"
|
||||
+ "(len={{ loop.length }}, revindex0={{ loop.revindex0 }}, index0={{ loop.index0 }}, val={{ i }})"
|
||||
+ "{% endfor %}]"
|
||||
"[{% for i in lst|reverse %}(len={{ loop.length }},"
|
||||
" revindex0={{ loop.revindex0 }}, index0={{ loop.index0 }}, val={{ i }})"
|
||||
"{% endfor %}]"
|
||||
)
|
||||
|
||||
|
||||
@ -34,20 +30,20 @@ def test_loop_idx0():
|
||||
|
||||
def test_loopcontext0():
|
||||
in_lst = []
|
||||
l = LoopContext(reversed(in_lst), None)
|
||||
assert l.length == len(in_lst)
|
||||
lc = LoopContext(reversed(in_lst), None)
|
||||
assert lc.length == len(in_lst)
|
||||
|
||||
|
||||
def test_loopcontext1():
|
||||
in_lst = [10]
|
||||
l = LoopContext(reversed(in_lst), None)
|
||||
assert l.length == len(in_lst)
|
||||
lc = LoopContext(reversed(in_lst), None)
|
||||
assert lc.length == len(in_lst)
|
||||
|
||||
|
||||
def test_loopcontext2():
|
||||
in_lst = [10, 11]
|
||||
l = LoopContext(reversed(in_lst), None)
|
||||
assert l.length == len(in_lst)
|
||||
lc = LoopContext(reversed(in_lst), None)
|
||||
assert lc.length == len(in_lst)
|
||||
|
||||
|
||||
def test_iterator_not_advanced_early():
|
||||
|
||||
@ -36,8 +36,11 @@ class PrivateStuff(object):
|
||||
|
||||
|
||||
class PublicStuff(object):
|
||||
bar = lambda self: 23
|
||||
_foo = lambda self: 42
|
||||
def bar(self):
|
||||
return 23
|
||||
|
||||
def _foo(self):
|
||||
return 42
|
||||
|
||||
def __repr__(self):
|
||||
return "PublicStuff"
|
||||
|
||||
@ -195,9 +195,8 @@ class TestTestsCase(object):
|
||||
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)' }}"
|
||||
"{{ 'us-west-1' is matching '(us-east-1|ap-northeast-1)'"
|
||||
" or 'stage' is matching '(dev|stage)' }}"
|
||||
)
|
||||
assert tmpl.render() == "False"
|
||||
assert items == [
|
||||
|
||||
@ -51,14 +51,14 @@ class TestLRUCache(object):
|
||||
cache = LRUCache(3)
|
||||
cache["b"] = 1
|
||||
cache["a"] = 2
|
||||
values = [v for v in cache.itervalues()]
|
||||
values = [v for v in cache.values()]
|
||||
assert len(values) == 2
|
||||
assert 1 in values
|
||||
assert 2 in values
|
||||
|
||||
def test_itervalues_empty(self):
|
||||
cache = LRUCache(2)
|
||||
values = [v for v in cache.itervalues()]
|
||||
values = [v for v in cache.values()]
|
||||
assert len(values) == 0
|
||||
|
||||
def test_pickleable(self):
|
||||
@ -106,17 +106,17 @@ 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.values() == list(d.itervalues()) == [3, 2, 1]
|
||||
assert d.items() == [("c", 3), ("b", 2), ("a", 1)]
|
||||
assert d.keys() == ["c", "b", "a"]
|
||||
assert d.values() == [3, 2, 1]
|
||||
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.values() == list(d.itervalues()) == [4, 2, 3]
|
||||
assert d.items() == [("a", 4), ("b", 2), ("c", 3)]
|
||||
assert d.keys() == ["a", "b", "c"]
|
||||
assert d.values() == [4, 2, 3]
|
||||
assert list(reversed(d)) == ["c", "b", "a"]
|
||||
|
||||
def test_setdefault(self):
|
||||
@ -152,11 +152,11 @@ class TestHelpers(object):
|
||||
|
||||
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("foo.html")
|
||||
assert func("foo.htm")
|
||||
assert not func("foo.txt")
|
||||
assert func("FOO.HTML")
|
||||
assert not func("FOO.TXT")
|
||||
|
||||
|
||||
@pytest.mark.utils
|
||||
|
||||
Loading…
Reference in New Issue
Block a user