"groupby": do_groupby,
"join": do_join,
"list": do_list,
- # we intentionally do not support do_last because that would be
- # ridiculous
+ # we intentionally do not support do_last because it may not be safe in async
"reject": do_reject,
"rejectattr": do_rejectattr,
"map": do_map,
# -*- coding: utf-8 -*-
-"""The code for async support. Importing this patches Jinja on supported
-Python versions.
-"""
+"""The code for async support. Importing this patches Jinja."""
import asyncio
import inspect
from functools import update_wrapper
from .runtime import exported
+ self.writeline("from __future__ import generator_stop") # Python < 3.7
self.writeline("from jinja2.runtime import " + ", ".join(exported))
if self.environment.is_async:
if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated:
exc_value.translated = True
exc_value.source = source
-
- try:
- # Remove the old traceback on Python 3, otherwise the frames
- # from the compiler still show up.
- exc_value.with_traceback(None)
- except AttributeError:
- pass
-
+ # Remove the old traceback, otherwise the frames from the
+ # compiler still show up.
+ exc_value.with_traceback(None)
# Outside of runtime, so the frame isn't executing template
# code, but it still needs to point at the template.
tb = fake_traceback(
for attr in (
"argcount",
"posonlyargcount", # Python 3.8
- "kwonlyargcount", # Python 3
+ "kwonlyargcount",
"nlocals",
"stacksize",
"flags",
See :ref:`bytecode-cache` for more information.
`enable_async`
- If set to true this enables async template execution which allows
- you to take advantage of newer Python features. This requires
- Python 3.6 or later.
+ If set to true this enables async template execution which
+ allows using async functions and generators.
"""
#: if this environment is sandboxed. Modifying this variable won't make
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.
+ """Invokes a filter on a value the same way the compiler does.
- Note that on Python 3 this might return a coroutine in case the
- filter is running from an environment in async mode and the filter
- supports async execution. It's your responsibility to await this
- if needed.
+ This might return a coroutine if the filter is running from an
+ environment in async mode and the filter supports async
+ execution. It's your responsibility to await this if needed.
.. versionadded:: 2.7
"""
return "%.1f %s" % ((base * bytes / unit), prefix)
-def do_pprint(value, verbose=False):
- """Pretty print a variable. Useful for debugging.
-
- With Jinja 1.2 onwards you can pass it a parameter. If this parameter
- is truthy the output will be more verbose (this requires `pretty`)
- """
- return pformat(value, verbose=verbose)
+def do_pprint(value):
+ """Pretty print a variable. Useful for debugging."""
+ return pformat(value)
@evalcontextfilter
{{ mytext|urlize(40, target='_blank') }}
- .. versionchanged:: 2.8+
- The *target* parameter was added.
+ .. versionchanged:: 2.8
+ The ``target`` parameter was added.
"""
policies = eval_ctx.environment.policies
rel = set((rel or "").split() or [])
from operator import itemgetter
from sys import intern
+from ._identifier import pattern as name_re
from .exceptions import TemplateSyntaxError
from .utils import LRUCache
re.IGNORECASE | re.VERBOSE,
)
-try:
- # check if this Python supports Unicode identifiers
- compile("föö", "<unknown>", "eval")
-except SyntaxError:
- # Python 2, no Unicode support, use ASCII identifiers
- name_re = re.compile(r"[a-zA-Z_][a-zA-Z0-9_]*")
- check_ident = False
-else:
- # Unicode support, import generated re pattern and set flag to use
- # str.isidentifier to validate during lexing.
- from ._identifier import pattern as name_re
-
- check_ident = True
-
# internal the tokens and keep references to them
TOKEN_ADD = intern("add")
TOKEN_ASSIGN = intern("assign")
token = value
elif token == TOKEN_NAME:
value = str(value)
- if check_ident and not value.isidentifier():
+ if not value.isidentifier():
raise TemplateSyntaxError(
"Invalid character in identifier", lineno, name, filename
)
return self
def __eq__(self, other):
- return type(self) is type(other) and tuple(self.iter_fields()) == tuple(
- other.iter_fields()
- )
+ if type(self) is not type(other):
+ return NotImplemented
- def __ne__(self, other):
- return not self.__eq__(other)
+ return tuple(self.iter_fields()) == tuple(other.iter_fields())
- # Restore Python 2 hashing behavior on Python 3
- __hash__ = object.__hash__
+ def __hash__(self):
+ return hash(tuple(self.iter_fields()))
def __repr__(self):
return "%s(%s)" % (
if eval_ctx.volatile or self.node is None:
raise Impossible()
- # we have to be careful here because we call filter_ below.
- # if this variable would be called filter, 2to3 would wrap the
- # call in a list because it is assuming we are talking about the
- # builtin filter function here which no longer returns a list in
- # 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) is True:
"""
import operator
import types
+from _string import formatter_field_name_split
from collections import abc
from collections import deque
from string import Formatter
def modifies_known_mutable(obj, attr):
"""This function checks if an attribute on a builtin mutable object
- (list, dict, set or deque) would modify it if called. It also supports
- the "user"-versions of the objects (`sets.Set`, `UserDict.*` etc.) and
- with Python 2.6 onwards the abstract base classes `MutableSet`,
- `MutableMapping`, and `MutableSequence`.
+ (list, dict, set or deque) or the corresponding ABCs would modify it
+ if called.
>>> modifies_known_mutable({}, "clear")
True
return not modifies_known_mutable(obj, attr)
-# This really is not a public API apparently.
-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
return "%s object" % name
-def pformat(obj, verbose=False):
- """Prettyprint an object. Either use the `pretty` library or the
- builtin `pprint`.
+def pformat(obj):
+ """Format an object using :func:`pprint.pformat`.
"""
- try:
- from pretty import pretty
-
- return pretty(obj, verbose=verbose)
- except ImportError:
- from pprint import pformat
+ from pprint import pformat
- return pformat(obj)
+ return pformat(obj)
def urlize(text, trim_url_limit=None, rel=None, target=None):
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|attr("items")()|list }}')
from jinja2.ext import babel_extract
source = BytesIO(
+ b"""
+ {{ gettext('Hello World') }}
+ {% trans %}Hello World{% endtrans %}
+ {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
"""
- {{ 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", []),
from jinja2.ext import babel_extract
source = BytesIO(
+ b"""
+ {{ gettext(' Hello \n World') }}
+ {% trans trimmed %} Hello \n World{% endtrans %}
+ {% trans trimmed %}{{ users }} \n user
+ {%- pluralize %}{{ users }} \n users{% endtrans %}
"""
- {{ 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", []),
from jinja2.ext import babel_extract
source = BytesIO(
+ b"""
+ {{ gettext(' Hello \n World') }}
+ {% trans %} Hello \n World{% endtrans %}
+ {% trans %}{{ users }} \n user
+ {%- pluralize %}{{ users }} \n users{% endtrans %}
"""
- {{ 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", []),
from jinja2.ext import babel_extract
source = BytesIO(
+ b"""
+ {# trans first #}
+ {{ gettext('Hello World') }}
+ {% trans %}Hello World{% endtrans %}{# trans second #}
+ {#: third #}
+ {% trans %}{{ users }} user{% pluralize %}{{ users }} users{% endtrans %}
"""
- {# 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", ":"], {})
) == [
@pytest.mark.sandbox
-@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()