diff --git a/third_party/python/Jinja2/CHANGES.rst b/third_party/python/Jinja2/CHANGES.rst index 51f49845c21f..9b8b24ee030c 100644 --- a/third_party/python/Jinja2/CHANGES.rst +++ b/third_party/python/Jinja2/CHANGES.rst @@ -1,5 +1,38 @@ .. currentmodule:: jinja2 +Version 2.11.2 +-------------- + +Released 2020-04-13 + +- Fix a bug that caused callable objects with ``__getattr__``, like + :class:`~unittest.mock.Mock` to be treated as a + :func:`contextfunction`. :issue:`1145` +- Update ``wordcount`` filter to trigger :class:`Undefined` methods + by wrapping the input in :func:`soft_unicode`. :pr:`1160` +- Fix a hang when displaying tracebacks on Python 32-bit. + :issue:`1162` +- Showing an undefined error for an object that raises + ``AttributeError`` on access doesn't cause a recursion error. + :issue:`1177` +- Revert changes to :class:`~loaders.PackageLoader` from 2.10 which + removed the dependency on setuptools and pkg_resources, and added + limited support for namespace packages. The changes caused issues + when using Pytest. Due to the difficulty in supporting Python 2 and + :pep:`451` simultaneously, the changes are reverted until 3.0. + :pr:`1182` +- Fix line numbers in error messages when newlines are stripped. + :pr:`1178` +- The special ``namespace()`` assignment object in templates works in + async environments. :issue:`1180` +- Fix whitespace being removed before tags in the middle of lines when + ``lstrip_blocks`` is enabled. :issue:`1138` +- :class:`~nativetypes.NativeEnvironment` doesn't evaluate + intermediate strings during rendering. This prevents early + evaluation which could change the value of an expression. + :issue:`1186` + + Version 2.11.1 -------------- diff --git a/third_party/python/Jinja2/PKG-INFO b/third_party/python/Jinja2/PKG-INFO index 1b71b8cb806e..87f815183184 100644 --- a/third_party/python/Jinja2/PKG-INFO +++ b/third_party/python/Jinja2/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: Jinja2 -Version: 2.11.1 +Version: 2.11.2 Summary: A very fast and expressive template engine. Home-page: https://palletsprojects.com/p/jinja/ Author: Armin Ronacher diff --git a/third_party/python/Jinja2/examples/basic/cycle.py b/third_party/python/Jinja2/examples/basic/cycle.py new file mode 100644 index 000000000000..25dcb0b090ec --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/cycle.py @@ -0,0 +1,18 @@ +from __future__ import print_function + +from jinja2 import Environment + +env = Environment( + line_statement_prefix="#", variable_start_string="${", variable_end_string="}" +) +print( + env.from_string( + """\ +\ +""" + ).render() +) diff --git a/third_party/python/Jinja2/examples/basic/debugger.py b/third_party/python/Jinja2/examples/basic/debugger.py new file mode 100644 index 000000000000..d3c1a60a7ae8 --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/debugger.py @@ -0,0 +1,8 @@ +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") +print(tmpl.render(seq=[3, 2, 4, 5, 3, 2, 0, 2, 1])) diff --git a/third_party/python/Jinja2/examples/basic/inheritance.py b/third_party/python/Jinja2/examples/basic/inheritance.py new file mode 100644 index 000000000000..4a881bf8a87c --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/inheritance.py @@ -0,0 +1,15 @@ +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()) diff --git a/third_party/python/Jinja2/examples/basic/templates/broken.html b/third_party/python/Jinja2/examples/basic/templates/broken.html new file mode 100644 index 000000000000..294d5c99894d --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/templates/broken.html @@ -0,0 +1,6 @@ +{% from 'subbroken.html' import may_break %} + diff --git a/third_party/python/Jinja2/examples/basic/templates/subbroken.html b/third_party/python/Jinja2/examples/basic/templates/subbroken.html new file mode 100644 index 000000000000..245eb7e6e6f7 --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/templates/subbroken.html @@ -0,0 +1,3 @@ +{% macro may_break(item) -%} + [{{ item / 0 }}] +{%- endmacro %} diff --git a/third_party/python/Jinja2/examples/basic/test.py b/third_party/python/Jinja2/examples/basic/test.py new file mode 100644 index 000000000000..80b9d1f052b3 --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/test.py @@ -0,0 +1,31 @@ +from __future__ import print_function + +from jinja2 import Environment +from jinja2.loaders import DictLoader + +env = Environment( + loader=DictLoader( + { + "child.html": u"""\ +{% extends master_layout or 'master.html' %} +{% include helpers = 'helpers.html' %} +{% macro get_the_answer() %}42{% endmacro %} +{% title = 'Hello World' %} +{% block body %} + {{ get_the_answer() }} + {{ helpers.conspirate() }} +{% endblock %} +""", + "master.html": u"""\ + +{{ title }} +{% block body %}{% endblock %} +""", + "helpers.html": u"""\ +{% macro conspirate() %}23{% endmacro %} +""", + } + ) +) +tmpl = env.get_template("child.html") +print(tmpl.render()) diff --git a/third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py b/third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py new file mode 100644 index 000000000000..673b67ed76ae --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/test_filter_and_linestatements.py @@ -0,0 +1,29 @@ +from __future__ import print_function + +from jinja2 import Environment + +env = Environment( + line_statement_prefix="%", variable_start_string="${", variable_end_string="}" +) +tmpl = env.from_string( + """\ +% macro foo() + ${caller(42)} +% endmacro + +% call(var) foo() + [${var}] +% endcall +% filter escape + + % for item in [1, 2, 3] + - ${item} + % endfor +% endfilter +""" +) +print(tmpl.render(seq=range(10))) diff --git a/third_party/python/Jinja2/examples/basic/test_loop_filter.py b/third_party/python/Jinja2/examples/basic/test_loop_filter.py new file mode 100644 index 000000000000..39be08d61c2b --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/test_loop_filter.py @@ -0,0 +1,15 @@ +from __future__ import print_function + +from jinja2 import Environment + +tmpl = Environment().from_string( + """\ + +if condition: {{ 1 if foo else 0 }} +""" +) +print(tmpl.render(foo=True)) diff --git a/third_party/python/Jinja2/examples/basic/translate.py b/third_party/python/Jinja2/examples/basic/translate.py new file mode 100644 index 000000000000..71547f4649ca --- /dev/null +++ b/third_party/python/Jinja2/examples/basic/translate.py @@ -0,0 +1,20 @@ +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", +}[n == 1 and s or p] +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]) +) diff --git a/third_party/python/Jinja2/src/jinja2/__init__.py b/third_party/python/Jinja2/src/jinja2/__init__.py index 7f4a1c55a837..1229ba4275a0 100644 --- a/third_party/python/Jinja2/src/jinja2/__init__.py +++ b/third_party/python/Jinja2/src/jinja2/__init__.py @@ -41,4 +41,4 @@ from .utils import evalcontextfunction from .utils import is_undefined from .utils import select_autoescape -__version__ = "2.11.1" +__version__ = "2.11.2" diff --git a/third_party/python/Jinja2/src/jinja2/asyncfilters.py b/third_party/python/Jinja2/src/jinja2/asyncfilters.py index d29f6c62d2e5..3d98dbcc00de 100644 --- a/third_party/python/Jinja2/src/jinja2/asyncfilters.py +++ b/third_party/python/Jinja2/src/jinja2/asyncfilters.py @@ -26,17 +26,16 @@ 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 True: 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 + has_evalctxfilter = getattr(normal_filter, "evalcontextfilter", False) is True + has_ctxfilter = getattr(normal_filter, "contextfilter", False) is True + wrap_evalctx = not has_evalctxfilter and not has_ctxfilter def is_async(args): return args[0].environment.is_async diff --git a/third_party/python/Jinja2/src/jinja2/compiler.py b/third_party/python/Jinja2/src/jinja2/compiler.py index f450ec6e314d..63297b42c30f 100644 --- a/third_party/python/Jinja2/src/jinja2/compiler.py +++ b/third_party/python/Jinja2/src/jinja2/compiler.py @@ -1307,13 +1307,13 @@ class CodeGenerator(NodeVisitor): def finalize(value): return default(env_finalize(value)) - if getattr(env_finalize, "contextfunction", False): + if getattr(env_finalize, "contextfunction", False) is True: src += "context, " finalize = None # noqa: F811 - elif getattr(env_finalize, "evalcontextfunction", False): + elif getattr(env_finalize, "evalcontextfunction", False) is True: src += "context.eval_ctx, " finalize = None - elif getattr(env_finalize, "environmentfunction", False): + elif getattr(env_finalize, "environmentfunction", False) is True: src += "environment, " def finalize(value): @@ -1689,11 +1689,11 @@ class CodeGenerator(NodeVisitor): 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): + if getattr(func, "contextfilter", False) is True: self.write("context, ") - elif getattr(func, "evalcontextfilter", False): + elif getattr(func, "evalcontextfilter", False) is True: self.write("context.eval_ctx, ") - elif getattr(func, "environmentfilter", False): + elif getattr(func, "environmentfilter", False) is True: self.write("environment, ") # if the filter node is None we are inside a filter block diff --git a/third_party/python/Jinja2/src/jinja2/debug.py b/third_party/python/Jinja2/src/jinja2/debug.py index d2c5a06bf6c1..5d8aec31d05d 100644 --- a/third_party/python/Jinja2/src/jinja2/debug.py +++ b/third_party/python/Jinja2/src/jinja2/debug.py @@ -245,10 +245,7 @@ else: class _CTraceback(ctypes.Structure): _fields_ = [ # Extra PyObject slots when compiled with Py_TRACE_REFS. - ( - "PyObject_HEAD", - ctypes.c_byte * (32 if hasattr(sys, "getobjects") else 16), - ), + ("PyObject_HEAD", ctypes.c_byte * object().__sizeof__()), # Only care about tb_next as an object, not a traceback. ("tb_next", ctypes.py_object), ] diff --git a/third_party/python/Jinja2/src/jinja2/environment.py b/third_party/python/Jinja2/src/jinja2/environment.py index bf44b9deb4a1..8430390eeab4 100644 --- a/third_party/python/Jinja2/src/jinja2/environment.py +++ b/third_party/python/Jinja2/src/jinja2/environment.py @@ -492,20 +492,20 @@ class Environment(object): if func is None: fail_for_missing_callable("no filter named %r", name) args = [value] + list(args or ()) - if getattr(func, "contextfilter", False): + if getattr(func, "contextfilter", False) is True: if context is None: raise TemplateRuntimeError( "Attempted to invoke context filter without context" ) args.insert(0, context) - elif getattr(func, "evalcontextfilter", False): + elif getattr(func, "evalcontextfilter", False) is True: 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) is True: args.insert(0, self) return func(*args, **(kwargs or {})) diff --git a/third_party/python/Jinja2/src/jinja2/filters.py b/third_party/python/Jinja2/src/jinja2/filters.py index 1af7ac88a7c9..974156735123 100644 --- a/third_party/python/Jinja2/src/jinja2/filters.py +++ b/third_party/python/Jinja2/src/jinja2/filters.py @@ -761,7 +761,7 @@ def do_wordwrap( def do_wordcount(s): """Count the words in that string.""" - return len(_word_re.findall(s)) + return len(_word_re.findall(soft_unicode(s))) def do_int(value, default=0, base=10): diff --git a/third_party/python/Jinja2/src/jinja2/lexer.py b/third_party/python/Jinja2/src/jinja2/lexer.py index a2b44e926b06..552356a12d1d 100644 --- a/third_party/python/Jinja2/src/jinja2/lexer.py +++ b/third_party/python/Jinja2/src/jinja2/lexer.py @@ -681,6 +681,8 @@ class Lexer(object): source_length = len(source) balancing_stack = [] lstrip_unless_re = self.lstrip_unless_re + newlines_stripped = 0 + line_starting = True while 1: # tokenizer loop @@ -717,7 +719,9 @@ class Lexer(object): if strip_sign == "-": # Strip all whitespace between the text and the tag. - groups = (text.rstrip(),) + groups[1:] + stripped = text.rstrip() + newlines_stripped = text[len(stripped) :].count("\n") + groups = (stripped,) + groups[1:] elif ( # Not marked for preserving whitespace. strip_sign != "+" @@ -728,11 +732,11 @@ class Lexer(object): ): # The start of text between the last newline and the tag. l_pos = text.rfind("\n") + 1 - - # If there's only whitespace between the newline and the - # tag, strip it. - if not lstrip_unless_re.search(text, l_pos): - groups = (text[:l_pos],) + groups[1:] + if l_pos > 0 or line_starting: + # If there's only whitespace between the newline and the + # tag, strip it. + if not lstrip_unless_re.search(text, l_pos): + groups = (text[:l_pos],) + groups[1:] for idx, token in enumerate(tokens): # failure group @@ -758,7 +762,8 @@ class Lexer(object): data = groups[idx] if data or token not in ignore_if_empty: yield lineno, token, data - lineno += data.count("\n") + lineno += data.count("\n") + newlines_stripped + newlines_stripped = 0 # strings as token just are yielded as it. else: @@ -790,6 +795,8 @@ class Lexer(object): yield lineno, tokens, data lineno += data.count("\n") + line_starting = m.group()[-1:] == "\n" + # fetch new position into new variable so that we can check # if there is a internal parsing error which would result # in an infinite loop diff --git a/third_party/python/Jinja2/src/jinja2/loaders.py b/third_party/python/Jinja2/src/jinja2/loaders.py index ce5537a03c0e..457c4b59a721 100644 --- a/third_party/python/Jinja2/src/jinja2/loaders.py +++ b/third_party/python/Jinja2/src/jinja2/loaders.py @@ -3,11 +3,9 @@ sources. """ import os -import pkgutil import sys import weakref from hashlib import sha1 -from importlib import import_module from os import path from types import ModuleType @@ -217,141 +215,75 @@ class FileSystemLoader(BaseLoader): class PackageLoader(BaseLoader): - """Load templates from a directory in a Python package. + """Load templates from python eggs or packages. It is constructed with + the name of the python package and the path to the templates in that + package:: - :param package_name: Import name of the package that contains the - template directory. - :param package_path: Directory within the imported package that - contains the templates. - :param encoding: Encoding of template files. + loader = PackageLoader('mypackage', 'views') - The following example looks up templates in the ``pages`` directory - within the ``project.ui`` package. + If the package path is not given, ``'templates'`` is assumed. - .. code-block:: python - - loader = PackageLoader("project.ui", "pages") - - Only packages installed as directories (standard pip behavior) or - zip/egg files (less common) are supported. The Python API for - introspecting data in packages is too limited to support other - installation methods the way this loader requires. - - There is limited support for :pep:`420` namespace packages. The - template directory is assumed to only be in one namespace - contributor. Zip files contributing to a namespace are not - supported. - - .. versionchanged:: 2.11.0 - No longer uses ``setuptools`` as a dependency. - - .. versionchanged:: 2.11.0 - Limited PEP 420 namespace package support. + Per default the template encoding is ``'utf-8'`` which can be changed + by setting the `encoding` parameter to something else. Due to the nature + of eggs it's only possible to reload templates if the package was loaded + from the file system and not a zip file. """ def __init__(self, package_name, package_path="templates", encoding="utf-8"): - if package_path == os.path.curdir: - package_path = "" - elif package_path[:2] == os.path.curdir + os.path.sep: - package_path = package_path[2:] + from pkg_resources import DefaultProvider + from pkg_resources import get_provider + from pkg_resources import ResourceManager - package_path = os.path.normpath(package_path).rstrip(os.path.sep) - self.package_path = package_path - self.package_name = package_name + provider = get_provider(package_name) self.encoding = encoding - - # Make sure the package exists. This also makes namespace - # packages work, otherwise get_loader returns None. - import_module(package_name) - self._loader = loader = pkgutil.get_loader(package_name) - - # Zip loader's archive attribute points at the zip. - self._archive = getattr(loader, "archive", None) - self._template_root = None - - if hasattr(loader, "get_filename"): - # A standard directory package, or a zip package. - self._template_root = os.path.join( - os.path.dirname(loader.get_filename(package_name)), package_path - ) - elif hasattr(loader, "_path"): - # A namespace package, limited support. Find the first - # contributor with the template directory. - for root in loader._path: - root = os.path.join(root, package_path) - - if os.path.isdir(root): - self._template_root = root - break - - if self._template_root is None: - raise ValueError( - "The %r package was not installed in a way that" - " PackageLoader understands." % package_name - ) + self.manager = ResourceManager() + self.filesystem_bound = isinstance(provider, DefaultProvider) + self.provider = provider + self.package_path = package_path def get_source(self, environment, template): - p = os.path.join(self._template_root, *split_template_path(template)) + pieces = split_template_path(template) + p = "/".join((self.package_path,) + tuple(pieces)) - if self._archive is None: - # Package is a directory. - if not os.path.isfile(p): - raise TemplateNotFound(template) + if not self.provider.has_resource(p): + raise TemplateNotFound(template) - with open(p, "rb") as f: - source = f.read() + filename = uptodate = None - mtime = os.path.getmtime(p) + if self.filesystem_bound: + filename = self.provider.get_resource_filename(self.manager, p) + mtime = path.getmtime(filename) - def up_to_date(): - return os.path.isfile(p) and os.path.getmtime(p) == mtime + def uptodate(): + try: + return path.getmtime(filename) == mtime + except OSError: + return False - else: - # Package is a zip file. - try: - source = self._loader.get_data(p) - except OSError: - raise TemplateNotFound(template) - - # Could use the zip's mtime for all template mtimes, but - # would need to safely reload the module if it's out of - # date, so just report it as always current. - up_to_date = None - - return source.decode(self.encoding), p, up_to_date + source = self.provider.get_resource_string(self.manager, p) + return source.decode(self.encoding), filename, uptodate def list_templates(self): + path = self.package_path + + if path[:2] == "./": + path = path[2:] + elif path == ".": + path = "" + + offset = len(path) results = [] - if self._archive is None: - # Package is a directory. - offset = len(self._template_root) + def _walk(path): + for filename in self.provider.resource_listdir(path): + fullname = path + "/" + filename - for dirpath, _, filenames in os.walk(self._template_root): - dirpath = dirpath[offset:].lstrip(os.path.sep) - results.extend( - os.path.join(dirpath, name).replace(os.path.sep, "/") - for name in filenames - ) - else: - if not hasattr(self._loader, "_files"): - raise TypeError( - "This zip import does not have the required" - " metadata to list templates." - ) - - # Package is a zip file. - prefix = ( - self._template_root[len(self._archive) :].lstrip(os.path.sep) - + os.path.sep - ) - offset = len(prefix) - - for name in self._loader._files.keys(): - # Find names under the templates directory that aren't directories. - if name.startswith(prefix) and name[-1] != os.path.sep: - results.append(name[offset:].replace(os.path.sep, "/")) + if self.provider.resource_isdir(fullname): + _walk(fullname) + else: + results.append(fullname[offset:].lstrip("/")) + _walk(path) results.sort() return results diff --git a/third_party/python/Jinja2/src/jinja2/nativetypes.py b/third_party/python/Jinja2/src/jinja2/nativetypes.py index 9866c962dcff..a9ead4e2bbf0 100644 --- a/third_party/python/Jinja2/src/jinja2/nativetypes.py +++ b/third_party/python/Jinja2/src/jinja2/nativetypes.py @@ -1,4 +1,3 @@ -import types from ast import literal_eval from itertools import chain from itertools import islice @@ -11,7 +10,7 @@ from .environment import Environment from .environment import Template -def native_concat(nodes, preserve_quotes=True): +def native_concat(nodes): """Return a native Python type from the list of compiled nodes. If the result is a single node, its value is returned. Otherwise, the nodes are concatenated as strings. If the result can be parsed with @@ -19,9 +18,6 @@ def native_concat(nodes, preserve_quotes=True): the string is returned. :param nodes: Iterable of nodes to concatenate. - :param preserve_quotes: Whether to re-wrap literal strings with - quotes, to preserve quotes around expressions for later parsing. - Should be ``False`` in :meth:`NativeEnvironment.render`. """ head = list(islice(nodes, 2)) @@ -31,29 +27,17 @@ def native_concat(nodes, preserve_quotes=True): if len(head) == 1: raw = head[0] 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 chain(head, nodes)]) try: - literal = literal_eval(raw) + return literal_eval(raw) except (ValueError, SyntaxError, MemoryError): return raw - # If literal_eval returned a string, re-wrap with the original - # quote character to avoid dropping quotes between expression nodes. - # Without this, "'{{ a }}', '{{ b }}'" results in "a, b", but should - # be ('a', 'b'). - if preserve_quotes and isinstance(literal, str): - return "{quote}{}{quote}".format(literal, quote=raw[0]) - - return literal - class NativeCodeGenerator(CodeGenerator): """A code generator which renders Python types by not adding - ``to_string()`` around output nodes, and using :func:`native_concat` - to convert complex strings back to Python types if possible. + ``to_string()`` around output nodes. """ @staticmethod @@ -61,7 +45,7 @@ class NativeCodeGenerator(CodeGenerator): return value def _output_const_repr(self, group): - return repr(native_concat(group)) + return repr(u"".join([text_type(v) for v in group])) def _output_child_to_const(self, node, frame, finalize): const = node.as_const(frame.eval_ctx) @@ -100,10 +84,9 @@ class NativeTemplate(Template): Otherwise, the string is returned. """ vars = dict(*args, **kwargs) + try: - return native_concat( - self.root_render_func(self.new_context(vars)), preserve_quotes=False - ) + return native_concat(self.root_render_func(self.new_context(vars))) except Exception: return self.environment.handle_exception() diff --git a/third_party/python/Jinja2/src/jinja2/nodes.py b/third_party/python/Jinja2/src/jinja2/nodes.py index 9f3edc05f9f3..95bd614a140a 100644 --- a/third_party/python/Jinja2/src/jinja2/nodes.py +++ b/third_party/python/Jinja2/src/jinja2/nodes.py @@ -671,7 +671,7 @@ 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) is True: raise Impossible() # We cannot constant handle async filters, so we need to make sure @@ -684,9 +684,9 @@ class Filter(Expr): 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) is True: args.insert(0, eval_ctx) - elif getattr(filter_, "environmentfilter", False): + elif getattr(filter_, "environmentfilter", False) is True: args.insert(0, self.environment) try: diff --git a/third_party/python/Jinja2/src/jinja2/runtime.py b/third_party/python/Jinja2/src/jinja2/runtime.py index 527d4b5e4bf2..3ad79686242d 100644 --- a/third_party/python/Jinja2/src/jinja2/runtime.py +++ b/third_party/python/Jinja2/src/jinja2/runtime.py @@ -280,11 +280,11 @@ class Context(with_metaclass(ContextMeta)): break if callable(__obj): - if getattr(__obj, "contextfunction", 0): + if getattr(__obj, "contextfunction", False) is True: args = (__self,) + args - elif getattr(__obj, "evalcontextfunction", 0): + elif getattr(__obj, "evalcontextfunction", False) is True: args = (__self.eval_ctx,) + args - elif getattr(__obj, "environmentfunction", 0): + elif getattr(__obj, "environmentfunction", False) is True: args = (__self.environment,) + args try: return __obj(*args, **kwargs) diff --git a/third_party/python/Jinja2/src/jinja2/utils.py b/third_party/python/Jinja2/src/jinja2/utils.py index e3285e8edb45..b422ba9686fa 100644 --- a/third_party/python/Jinja2/src/jinja2/utils.py +++ b/third_party/python/Jinja2/src/jinja2/utils.py @@ -165,11 +165,15 @@ def object_type_repr(obj): return "None" elif obj is Ellipsis: return "Ellipsis" + + cls = type(obj) + # __builtin__ in 2.x, builtins in 3.x - if obj.__class__.__module__ in ("__builtin__", "builtins"): - name = obj.__class__.__name__ + if cls.__module__ in ("__builtin__", "builtins"): + name = cls.__name__ else: - name = obj.__class__.__module__ + "." + obj.__class__.__name__ + name = cls.__module__ + "." + cls.__name__ + return "%s object" % name @@ -693,7 +697,8 @@ class Namespace(object): self.__attrs = dict(*args, **kwargs) def __getattribute__(self, name): - if name == "_Namespace__attrs": + # __class__ is needed for the awaitable check in async mode + if name in {"_Namespace__attrs", "__class__"}: return object.__getattribute__(self, name) try: return self.__attrs[name] diff --git a/third_party/python/MarkupSafe/docs/Makefile b/third_party/python/MarkupSafe/docs/Makefile deleted file mode 100644 index 51285967a7d9..000000000000 --- a/third_party/python/MarkupSafe/docs/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line. -SPHINXOPTS = -SPHINXBUILD = sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/third_party/python/MarkupSafe/docs/changes.rst b/third_party/python/MarkupSafe/docs/changes.rst deleted file mode 100644 index 955deaf27bc8..000000000000 --- a/third_party/python/MarkupSafe/docs/changes.rst +++ /dev/null @@ -1,4 +0,0 @@ -Changes -======= - -.. include:: ../CHANGES.rst diff --git a/third_party/python/MarkupSafe/docs/conf.py b/third_party/python/MarkupSafe/docs/conf.py deleted file mode 100644 index f34984701bf4..000000000000 --- a/third_party/python/MarkupSafe/docs/conf.py +++ /dev/null @@ -1,42 +0,0 @@ -from pallets_sphinx_themes import get_version -from pallets_sphinx_themes import ProjectLink - -# Project -------------------------------------------------------------- - -project = "MarkupSafe" -copyright = "2010 Pallets Team" -author = "Pallets Team" -release, version = get_version("MarkupSafe") - -# General -------------------------------------------------------------- - -master_doc = "index" -extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx", "pallets_sphinx_themes"] -intersphinx_mapping = {"python": ("https://docs.python.org/3/", None)} - -# HTML ----------------------------------------------------------------- - -html_theme = "flask" -html_theme_options = {"index_sidebar_logo": False} -html_context = { - "project_links": [ - ProjectLink("Donate to Pallets", "https://palletsprojects.com/donate"), - ProjectLink("Website", "https://palletsprojects.com/p/markupsafe/"), - ProjectLink("PyPI releases", "https://pypi.org/project/MarkupSafe/"), - ProjectLink("Source Code", "https://github.com/pallets/markupsafe/"), - ProjectLink("Issue Tracker", "https://github.com/pallets/markupsafe/issues/"), - ] -} -html_sidebars = { - "index": ["project.html", "localtoc.html", "searchbox.html"], - "**": ["localtoc.html", "relations.html", "searchbox.html"], -} -singlehtml_sidebars = {"index": ["project.html", "localtoc.html"]} -html_title = "MarkupSafe Documentation ({})".format(version) -html_show_sourcelink = False - -# LaTeX ---------------------------------------------------------------- - -latex_documents = [ - (master_doc, "MarkupSafe-{}.tex".format(version), html_title, author, "manual") -] diff --git a/third_party/python/MarkupSafe/docs/escaping.rst b/third_party/python/MarkupSafe/docs/escaping.rst deleted file mode 100644 index d99674da87c0..000000000000 --- a/third_party/python/MarkupSafe/docs/escaping.rst +++ /dev/null @@ -1,21 +0,0 @@ -.. module:: markupsafe - -Working With Safe Text -====================== - -.. autofunction:: escape - -.. autoclass:: Markup - :members: escape, unescape, striptags - - -Optional Values ---------------- - -.. autofunction:: escape_silent - - -Convert an Object to a String ------------------------------ - -.. autofunction:: soft_unicode diff --git a/third_party/python/MarkupSafe/docs/formatting.rst b/third_party/python/MarkupSafe/docs/formatting.rst deleted file mode 100644 index c425134771b3..000000000000 --- a/third_party/python/MarkupSafe/docs/formatting.rst +++ /dev/null @@ -1,77 +0,0 @@ -.. currentmodule:: markupsafe - -String Formatting -================= - -The :class:`Markup` class can be used as a format string. Objects -formatted into a markup string will be escaped first. - - -Format Method -------------- - -The ``format`` method extends the standard :meth:`str.format` behavior -to use an ``__html_format__`` method. - -#. If an object has an ``__html_format__`` method, it is called as a - replacement for the ``__format__`` method. It is passed a format - specifier if it's given. The method must return a string or - :class:`Markup` instance. - -#. If an object has an ``__html__`` method, it is called. If a format - specifier was passed and the class defined ``__html__`` but not - ``__html_format__``, a ``ValueError`` is raised. - -#. Otherwise Python's default format behavior is used and the result - is escaped. - -For example, to implement a ``User`` that wraps its ``name`` in a -``span`` tag, and adds a link when using the ``'link'`` format -specifier: - -.. code-block:: python - - class User(object): - def __init__(self, id, name): - self.id = id - self.name = name - - def __html_format__(self, format_spec): - if format_spec == 'link': - return Markup( - '{}' - ).format(self.id, self.__html__()) - elif format_spec: - raise ValueError('Invalid format spec') - return self.__html__() - - def __html__(self): - return Markup( - '{0}' - ).format(self.name) - - -.. code-block:: pycon - - >>> user = User(3, '