Hello community, here is the log from the commit of package python-Jinja2 for openSUSE:Factory checked in at 2020-05-04 18:33:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-Jinja2 (Old) and /work/SRC/openSUSE:Factory/.python-Jinja2.new.2738 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-Jinja2" Mon May 4 18:33:18 2020 rev:40 rq:800008 version:2.11.2 Changes: -------- --- /work/SRC/openSUSE:Factory/python-Jinja2/python-Jinja2.changes 2020-04-14 16:28:48.915988662 +0200 +++ /work/SRC/openSUSE:Factory/.python-Jinja2.new.2738/python-Jinja2.changes 2020-05-04 18:33:48.164230349 +0200 @@ -1,0 +2,31 @@ +Mon May 4 09:35:51 UTC 2020 - Johannes Grassler <[email protected]> + +- update to 2.11.1 + * 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 + +------------------------------------------------------------------- Old: ---- Jinja2-2.11.1.tar.gz New: ---- Jinja2-2.11.2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-Jinja2.spec ++++++ --- /var/tmp/diff_new_pack.6uYTDT/_old 2020-05-04 18:33:50.168234410 +0200 +++ /var/tmp/diff_new_pack.6uYTDT/_new 2020-05-04 18:33:50.172234418 +0200 @@ -24,7 +24,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define oldpython python Name: python-Jinja2 -Version: 2.11.1 +Version: 2.11.2 Release: 0 Summary: A template engine written in pure Python License: BSD-3-Clause ++++++ Jinja2-2.11.1.tar.gz -> Jinja2-2.11.2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/CHANGES.rst new/Jinja2-2.11.2/CHANGES.rst --- old/Jinja2-2.11.1/CHANGES.rst 2020-01-30 19:05:13.000000000 +0100 +++ new/Jinja2-2.11.2/CHANGES.rst 2020-04-13 18:13:48.000000000 +0200 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/PKG-INFO new/Jinja2-2.11.2/PKG-INFO --- old/Jinja2-2.11.1/PKG-INFO 2020-01-30 19:07:56.746518400 +0100 +++ new/Jinja2-2.11.2/PKG-INFO 2020-04-13 18:14:13.635887100 +0200 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/docs/api.rst new/Jinja2-2.11.2/docs/api.rst --- old/Jinja2-2.11.1/docs/api.rst 2020-01-29 16:26:55.000000000 +0100 +++ new/Jinja2-2.11.2/docs/api.rst 2020-04-13 16:18:12.000000000 +0200 @@ -5,9 +5,10 @@ :noindex: :synopsis: public Jinja API -This document describes the API to Jinja and not the template language. It -will be most useful as reference to those implementing the template interface -to the application and not those who are creating Jinja templates. +This document describes the API to Jinja and not the template language +(for that, see :doc:`/templates`). It will be most useful as reference +to those implementing the template interface to the application and not +those who are creating Jinja templates. Basics ------ @@ -529,37 +530,38 @@ Async Support ------------- -Starting with version 2.9, Jinja also supports the Python `async` and -`await` constructs. As far as template designers go this feature is -entirely opaque to them however as a developer you should be aware of how -it's implemented as it influences what type of APIs you can safely expose -to the template environment. - -First you need to be aware that by default async support is disabled as -enabling it will generate different template code behind the scenes which -passes everything through the asyncio event loop. This is important to -understand because it has some impact to what you are doing: - -* template rendering will require an event loop to be set for the - current thread (``asyncio.get_event_loop`` needs to return one) -* all template generation code internally runs async generators which - means that you will pay a performance penalty even if the non sync - methods are used! -* The sync methods are based on async methods if the async mode is - enabled which means that `render` for instance will internally invoke - `render_async` and run it as part of the current event loop until the - execution finished. +.. versionadded:: 2.9 + +Jinja supports the Python ``async`` and ``await`` syntax. For the +template designer, this support (when enabled) is entirely transparent, +templates continue to look exactly the same. However, developers should +be aware of the implementation as it affects what types of APIs you can +use. + +By default, async support is disabled. Enabling it will cause the +environment to compile different code behind the scenes in order to +handle async and sync code in an asyncio event loop. This has the +following implications: + +- Template rendering requires an event loop to be available to the + current thread. :func:`asyncio.get_event_loop` must return an event + loop. +- The compiled code uses ``await`` for functions and attributes, and + uses ``async for`` loops. In order to support using both async and + sync functions in this context, a small wrapper is placed around + all calls and access, which add overhead compared to purely async + code. +- Sync methods and filters become wrappers around their corresponding + async implementations where needed. For example, ``render`` invokes + ``async_render``, and ``|map`` supports async iterables. Awaitable objects can be returned from functions in templates and any -function call in a template will automatically await the result. This -means that you can provide a method that asynchronously loads data -from a database if you so desire and from the template designer's point of -view this is just another function they can call. This means that the -``await`` you would normally issue in Python is implied. However this -only applies to function calls. If an attribute for instance would be an -awaitable object then this would not result in the expected behavior. +function call in a template will automatically await the result. The +``await`` you would normally add in Python is implied. For example, you +can provide a method that asynchronously loads data from a database, and +from the template designer's point of view it can be called like any +other function. -Likewise iterations with a `for` loop support async iterators. .. _policies: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/Jinja2.egg-info/PKG-INFO new/Jinja2-2.11.2/src/Jinja2.egg-info/PKG-INFO --- old/Jinja2-2.11.1/src/Jinja2.egg-info/PKG-INFO 2020-01-30 19:07:56.000000000 +0100 +++ new/Jinja2-2.11.2/src/Jinja2.egg-info/PKG-INFO 2020-04-13 18:14:13.000000000 +0200 @@ -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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/Jinja2.egg-info/SOURCES.txt new/Jinja2-2.11.2/src/Jinja2.egg-info/SOURCES.txt --- old/Jinja2-2.11.1/src/Jinja2.egg-info/SOURCES.txt 2020-01-30 19:07:56.000000000 +0100 +++ new/Jinja2-2.11.2/src/Jinja2.egg-info/SOURCES.txt 2020-04-13 18:14:13.000000000 +0200 @@ -91,7 +91,6 @@ tests/test_tests.py tests/test_utils.py tests/res/__init__.py -tests/res/package.zip tests/res/templates/broken.html tests/res/templates/mojibake.txt tests/res/templates/syntaxerror.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/__init__.py new/Jinja2-2.11.2/src/jinja2/__init__.py --- old/Jinja2-2.11.1/src/jinja2/__init__.py 2020-01-30 19:05:04.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/__init__.py 2020-04-13 18:12:03.000000000 +0200 @@ -41,4 +41,4 @@ from .utils import is_undefined from .utils import select_autoescape -__version__ = "2.11.1" +__version__ = "2.11.2" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/asyncfilters.py new/Jinja2-2.11.2/src/jinja2/asyncfilters.py --- old/Jinja2-2.11.1/src/jinja2/asyncfilters.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/asyncfilters.py 2020-04-13 16:18:12.000000000 +0200 @@ -26,17 +26,16 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/compiler.py new/Jinja2-2.11.2/src/jinja2/compiler.py --- old/Jinja2-2.11.1/src/jinja2/compiler.py 2020-01-30 18:55:16.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/compiler.py 2020-04-13 16:18:12.000000000 +0200 @@ -1307,13 +1307,13 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/debug.py new/Jinja2-2.11.2/src/jinja2/debug.py --- old/Jinja2-2.11.1/src/jinja2/debug.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/debug.py 2020-04-13 16:18:12.000000000 +0200 @@ -245,10 +245,7 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/environment.py new/Jinja2-2.11.2/src/jinja2/environment.py --- old/Jinja2-2.11.1/src/jinja2/environment.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/environment.py 2020-04-13 16:18:12.000000000 +0200 @@ -492,20 +492,20 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/filters.py new/Jinja2-2.11.2/src/jinja2/filters.py --- old/Jinja2-2.11.1/src/jinja2/filters.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/filters.py 2020-04-13 16:18:12.000000000 +0200 @@ -761,7 +761,7 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/lexer.py new/Jinja2-2.11.2/src/jinja2/lexer.py --- old/Jinja2-2.11.1/src/jinja2/lexer.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/lexer.py 2020-04-13 16:18:12.000000000 +0200 @@ -681,6 +681,8 @@ 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 @@ 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 @@ ): # 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 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/loaders.py new/Jinja2-2.11.2/src/jinja2/loaders.py --- old/Jinja2-2.11.1/src/jinja2/loaders.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/loaders.py 2020-04-13 16:18:12.000000000 +0200 @@ -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 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)) - - if self._archive is None: - # Package is a directory. - if not os.path.isfile(p): - raise TemplateNotFound(template) + pieces = split_template_path(template) + p = "/".join((self.package_path,) + tuple(pieces)) - with open(p, "rb") as f: - source = f.read() + if not self.provider.has_resource(p): + raise TemplateNotFound(template) - mtime = os.path.getmtime(p) + filename = uptodate = None - def up_to_date(): - return os.path.isfile(p) and os.path.getmtime(p) == mtime + if self.filesystem_bound: + filename = self.provider.get_resource_filename(self.manager, p) + mtime = path.getmtime(filename) - 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 + def uptodate(): + try: + return path.getmtime(filename) == mtime + except OSError: + return False - 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): - results = [] + path = self.package_path - if self._archive is None: - # Package is a directory. - offset = len(self._template_root) - - 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) + if path[:2] == "./": + path = path[2:] + elif path == ".": + path = "" + + offset = len(path) + results = [] - 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, "/")) + def _walk(path): + for filename in self.provider.resource_listdir(path): + fullname = path + "/" + filename + + if self.provider.resource_isdir(fullname): + _walk(fullname) + else: + results.append(fullname[offset:].lstrip("/")) + _walk(path) results.sort() return results diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/nativetypes.py new/Jinja2-2.11.2/src/jinja2/nativetypes.py --- old/Jinja2-2.11.1/src/jinja2/nativetypes.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/nativetypes.py 2020-04-13 18:11:28.000000000 +0200 @@ -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 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 @@ 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 @@ 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 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/nodes.py new/Jinja2-2.11.2/src/jinja2/nodes.py --- old/Jinja2-2.11.1/src/jinja2/nodes.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/nodes.py 2020-04-13 16:18:12.000000000 +0200 @@ -671,7 +671,7 @@ # 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/runtime.py new/Jinja2-2.11.2/src/jinja2/runtime.py --- old/Jinja2-2.11.1/src/jinja2/runtime.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/runtime.py 2020-04-13 16:18:12.000000000 +0200 @@ -280,11 +280,11 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/src/jinja2/utils.py new/Jinja2-2.11.2/src/jinja2/utils.py --- old/Jinja2-2.11.1/src/jinja2/utils.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/src/jinja2/utils.py 2020-04-13 16:18:12.000000000 +0200 @@ -165,11 +165,15 @@ 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 @@ 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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/conftest.py new/Jinja2-2.11.2/tests/conftest.py --- old/Jinja2-2.11.1/tests/conftest.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/conftest.py 2020-04-13 16:18:12.000000000 +0200 @@ -14,50 +14,6 @@ return False -def pytest_configure(config): - """Register custom marks for test categories.""" - custom_markers = [ - "api", - "byte_code_cache", - "core_tags", - "debug", - "escapeUrlizeTarget", - "ext", - "extended", - "filesystemloader", - "filter", - "for_loop", - "helpers", - "if_condition", - "imports", - "includes", - "inheritance", - "lexer", - "lexnparse", - "loaders", - "loremIpsum", - "lowlevel", - "lrucache", - "lstripblocks", - "macros", - "meta", - "moduleloader", - "parser", - "regression", - "sandbox", - "set", - "streaming", - "syntax", - "test_tests", - "tokenstream", - "undefined", - "utils", - "with_", - ] - for mark in custom_markers: - config.addinivalue_line("markers", mark + ": test category") - - @pytest.fixture def env(): """returns a new environment.""" Binary files old/Jinja2-2.11.1/tests/res/package.zip and new/Jinja2-2.11.2/tests/res/package.zip differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_api.py new/Jinja2-2.11.2/tests/test_api.py --- old/Jinja2-2.11.1/tests/test_api.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_api.py 2020-04-13 16:18:12.000000000 +0200 @@ -25,8 +25,6 @@ from jinja2.utils import evalcontextfunction [email protected] [email protected] class TestExtendedAPI(object): def test_item_and_attribute(self, env): from jinja2.sandbox import SandboxedEnvironment @@ -163,8 +161,6 @@ t.render(total=MAX_RANGE + 1) [email protected] [email protected] class TestMeta(object): def test_find_undeclared_variables(self, env): ast = env.parse("{% set foo = 42 %}{{ bar + foo }}") @@ -218,8 +214,6 @@ assert list(i) == ["foo.html", "bar.html", None] [email protected] [email protected] class TestStreaming(object): def test_basic_streaming(self, env): t = env.from_string( @@ -261,8 +255,6 @@ shutil.rmtree(tmp) [email protected] [email protected] class TestUndefined(object): def test_stopiteration_is_undefined(self): def test(): @@ -277,6 +269,21 @@ with pytest.raises(AttributeError): Undefined("Foo").__dict__ + def test_undefined_attribute_error(self): + # Django's LazyObject turns the __class__ attribute into a + # property that resolves the wrapped function. If that wrapped + # function raises an AttributeError, printing the repr of the + # object in the undefined message would cause a RecursionError. + class Error(object): + @property + def __class__(self): + raise AttributeError() + + u = Undefined(obj=Error(), name="hello") + + with pytest.raises(UndefinedError): + getattr(u, "recursion", None) + def test_logging_undefined(self): _messages = [] @@ -400,8 +407,6 @@ Undefined(obj=42, name="upper")() [email protected] [email protected] class TestLowLevel(object): def test_custom_code_generator(self): class CustomCodeGenerator(CodeGenerator): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_async.py new/Jinja2-2.11.2/tests/test_async.py --- old/Jinja2-2.11.1/tests/test_async.py 2020-01-30 18:55:16.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_async.py 2020-04-13 16:18:12.000000000 +0200 @@ -130,7 +130,6 @@ return env [email protected] class TestAsyncImports(object): def test_context_imports(self, test_env_async): t = test_env_async.from_string('{% import "module" as m %}{{ m.test() }}') @@ -180,8 +179,6 @@ assert not hasattr(m, "notthere") [email protected] [email protected] class TestAsyncIncludes(object): def test_context_include(self, test_env_async): t = test_env_async.from_string('{% include "header" %}') @@ -279,8 +276,6 @@ assert t.render().strip() == "(FOO)" [email protected]_tags [email protected]_loop class TestAsyncForLoop(object): def test_simple(self, test_env_async): tmpl = test_env_async.from_string("{% for item in seq %}{{ item }}{% endfor %}") @@ -583,3 +578,14 @@ def test_awaitable_property_slicing(self, test_env_async): t = test_env_async.from_string("{% for x in a.b[:1] %}{{ x }}{% endfor %}") assert t.render(a=dict(b=[1, 2, 3])) == "1" + + +def test_namespace_awaitable(test_env_async): + async def _test(): + t = test_env_async.from_string( + '{% set ns = namespace(foo="Bar") %}{{ ns.foo }}' + ) + actual = await t.render_async() + assert actual == "Bar" + + run(_test()) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_bytecode_cache.py new/Jinja2-2.11.2/tests/test_bytecode_cache.py --- old/Jinja2-2.11.1/tests/test_bytecode_cache.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_bytecode_cache.py 2020-04-13 16:18:12.000000000 +0200 @@ -14,7 +14,6 @@ return Environment(loader=package_loader, bytecode_cache=bytecode_cache) [email protected]_code_cache class TestByteCodeCache(object): def test_simple(self, env): tmpl = env.get_template("test.html") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_core_tags.py new/Jinja2-2.11.2/tests/test_core_tags.py --- old/Jinja2-2.11.1/tests/test_core_tags.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_core_tags.py 2020-04-13 16:18:12.000000000 +0200 @@ -13,8 +13,6 @@ return Environment(trim_blocks=True) [email protected]_tags [email protected]_loop class TestForLoop(object): def test_simple(self, env): tmpl = env.from_string("{% for item in seq %}{{ item }}{% endfor %}") @@ -305,8 +303,6 @@ assert tmpl.render(x=0, seq=[1, 2, 3]) == "919293" [email protected]_tags [email protected]_condition class TestIfCondition(object): def test_simple(self, env): tmpl = env.from_string("""{% if true %}...{% endif %}""") @@ -349,8 +345,6 @@ assert tmpl.render() == "1" [email protected]_tags [email protected] class TestMacros(object): def test_simple(self, env_trim): tmpl = env_trim.from_string( @@ -475,8 +469,6 @@ assert tmpl.module.m(1, x=7) == "1|7|7" [email protected]_tags [email protected] class TestSet(object): def test_normal(self, env_trim): tmpl = env_trim.from_string("{% set foo = 1 %}{{ foo }}") @@ -584,8 +576,6 @@ assert tmpl.module.foo == u"11" [email protected]_tags [email protected]_ class TestWith(object): def test_with(self, env): tmpl = env.from_string( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_debug.py new/Jinja2-2.11.2/tests/test_debug.py --- old/Jinja2-2.11.1/tests/test_debug.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_debug.py 2020-04-13 16:18:12.000000000 +0200 @@ -17,7 +17,6 @@ return Environment(loader=filesystem_loader) [email protected] class TestDebug(object): def assert_traceback_matches(self, callback, expected_tb): with pytest.raises(Exception) as exc_info: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_ext.py new/Jinja2-2.11.2/tests/test_ext.py --- old/Jinja2-2.11.1/tests/test_ext.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_ext.py 2020-04-13 16:18:12.000000000 +0200 @@ -167,7 +167,6 @@ yield Token(lineno, "data", token.value[pos:]) [email protected] class TestExtensions(object): def test_extend_late(self): env = Environment() @@ -267,7 +266,6 @@ assert "'{}'".format(value) in out [email protected] class TestInternationalization(object): def test_trans(self): tmpl = i18n_env.get_template("child.html") @@ -418,7 +416,6 @@ ] [email protected] class TestScope(object): def test_basic_scope_behavior(self): # This is what the old with statement compiled down to @@ -452,7 +449,6 @@ assert tmpl.render(b=3, e=4) == "1|2|2|4|5" [email protected] class TestNewstyleInternationalization(object): def test_trans(self): tmpl = newstyle_i18n_env.get_template("child.html") @@ -544,7 +540,6 @@ assert t.render() == "%(foo)s" [email protected] class TestAutoEscape(object): def test_scoped_setting(self): env = Environment(extensions=["jinja2.ext.autoescape"], autoescape=True) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_filters.py new/Jinja2-2.11.2/tests/test_filters.py --- old/Jinja2-2.11.1/tests/test_filters.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_filters.py 2020-04-13 16:18:12.000000000 +0200 @@ -6,6 +6,8 @@ from jinja2 import Environment from jinja2 import Markup +from jinja2 import StrictUndefined +from jinja2 import UndefinedError from jinja2._compat import implements_to_string from jinja2._compat import text_type @@ -29,7 +31,6 @@ return u"(%s,%s)" % (text_type(self.value1), text_type(self.value2)) [email protected] class TestFilter(object): def test_filter_calling(self, env): rv = env.call_filter("sum", [1, 2, 3]) @@ -370,6 +371,11 @@ tmpl = env.from_string('{{ "foo bar baz"|wordcount }}') assert tmpl.render() == "3" + strict_env = Environment(undefined=StrictUndefined) + t = strict_env.from_string("{{ s|wordcount }}") + with pytest.raises(UndefinedError): + t.render() + def test_block(self, env): tmpl = env.from_string("{% filter lower|escape %}<HEHE>{% endfilter %}") assert tmpl.render() == "<hehe>" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_imports.py new/Jinja2-2.11.2/tests/test_imports.py --- old/Jinja2-2.11.1/tests/test_imports.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_imports.py 2020-04-13 16:18:12.000000000 +0200 @@ -23,7 +23,6 @@ return env [email protected] class TestImports(object): def test_context_imports(self, test_env): t = test_env.from_string('{% import "module" as m %}{{ m.test() }}') @@ -94,8 +93,6 @@ assert not hasattr(m, "notthere") [email protected] [email protected] class TestIncludes(object): def test_context_include(self, test_env): t = test_env.from_string('{% include "header" %}') diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_inheritance.py new/Jinja2-2.11.2/tests/test_inheritance.py --- old/Jinja2-2.11.1/tests/test_inheritance.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_inheritance.py 2020-04-13 16:18:12.000000000 +0200 @@ -74,7 +74,6 @@ ) [email protected] class TestInheritance(object): def test_layout(self, env): tmpl = env.get_template("layout") @@ -233,7 +232,6 @@ assert rv == ["43", "44", "45"] [email protected] class TestBugFix(object): def test_fixed_macro_scoping_bug(self, env): assert ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_lexnparse.py new/Jinja2-2.11.2/tests/test_lexnparse.py --- old/Jinja2-2.11.1/tests/test_lexnparse.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_lexnparse.py 2020-04-13 16:18:12.000000000 +0200 @@ -27,8 +27,6 @@ jinja_string_repr = repr [email protected] [email protected] class TestTokenStream(object): test_tokens = [ Token(1, TOKEN_BLOCK_BEGIN, ""), @@ -57,8 +55,6 @@ ] [email protected] [email protected] class TestLexer(object): def test_raw1(self, env): tmpl = env.from_string( @@ -182,9 +178,25 @@ else: pytest.raises(TemplateSyntaxError, env.from_string, t) + def test_lineno_with_strip(self, env): + tokens = env.lex( + """\ +<html> + <body> + {%- block content -%} + <hr> + {{ item }} + {% endblock %} + </body> +</html>""" + ) + for tok in tokens: + lineno, token_type, value = tok + if token_type == "name" and value == "item": + assert lineno == 5 + break + [email protected] [email protected] class TestParser(object): def test_php_syntax(self, env): env = Environment("<?", "?>", "<?=", "?>", "<!--", "-->") @@ -318,8 +330,6 @@ assert_error("{% unknown_tag %}", "Encountered unknown tag 'unknown_tag'.") [email protected] [email protected] class TestSyntax(object): def test_call(self, env): env = Environment() @@ -575,8 +585,6 @@ assert tmpl.render(foo={"bar": 42}) == "42" [email protected] [email protected] class TestLstripBlocks(object): def test_lstrip(self, env): env = Environment(lstrip_blocks=True, trim_blocks=False) @@ -721,6 +729,98 @@ ) assert tmpl.render(seq=range(5)) == "".join("%s\n" % x for x in range(5)) + def test_lstrip_blocks_outside_with_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=False) + tmpl = env.from_string( + " {% if kvs %}(\n" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n" + " ){% endif %}" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == "(\na=1 b=2 \n )" + + def test_lstrip_trim_blocks_outside_with_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=True) + tmpl = env.from_string( + " {% if kvs %}(\n" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n" + " ){% endif %}" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == "(\na=1 b=2 )" + + def test_lstrip_blocks_inside_with_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=False) + tmpl = env.from_string( + " ({% if kvs %}\n" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n" + " {% endif %})" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == " (\na=1 b=2 \n)" + + def test_lstrip_trim_blocks_inside_with_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=True) + tmpl = env.from_string( + " ({% if kvs %}\n" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}\n" + " {% endif %})" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == " (a=1 b=2 )" + + def test_lstrip_blocks_without_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=False) + tmpl = env.from_string( + " {% if kvs %}" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}" + " {% endif %}" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == " a=1 b=2 " + + def test_lstrip_trim_blocks_without_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=True) + tmpl = env.from_string( + " {% if kvs %}" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor %}" + " {% endif %}" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == " a=1 b=2 " + + def test_lstrip_blocks_consume_after_without_new_line(self): + env = Environment(lstrip_blocks=True, trim_blocks=False) + tmpl = env.from_string( + " {% if kvs -%}" + " {% for k, v in kvs %}{{ k }}={{ v }} {% endfor -%}" + " {% endif -%}" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == "a=1 b=2 " + + def test_lstrip_trim_blocks_consume_before_without_new_line(self): + env = Environment(lstrip_blocks=False, trim_blocks=False) + tmpl = env.from_string( + " {%- if kvs %}" + " {%- for k, v in kvs %}{{ k }}={{ v }} {% endfor -%}" + " {%- endif %}" + ) + out = tmpl.render(kvs=[("a", 1), ("b", 2)]) + assert out == "a=1 b=2 " + + def test_lstrip_trim_blocks_comment(self): + env = Environment(lstrip_blocks=True, trim_blocks=True) + tmpl = env.from_string(" {# 1 space #}\n {# 2 spaces #} {# 4 spaces #}") + out = tmpl.render() + assert out == " " * 4 + + def test_lstrip_trim_blocks_raw(self): + env = Environment(lstrip_blocks=True, trim_blocks=True) + tmpl = env.from_string("{{x}}\n{%- raw %} {% endraw -%}\n{{ y }}") + out = tmpl.render(x=1, y=2) + assert out == "1 2" + def test_php_syntax_with_manual(self, env): env = Environment( "<?", "?>", "<?=", "?>", "<!--", "-->", lstrip_blocks=True, trim_blocks=True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_loader.py new/Jinja2-2.11.2/tests/test_loader.py --- old/Jinja2-2.11.1/tests/test_loader.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_loader.py 2020-04-13 16:18:12.000000000 +0200 @@ -10,14 +10,12 @@ from jinja2 import Environment from jinja2 import loaders -from jinja2 import PackageLoader from jinja2._compat import PY2 from jinja2._compat import PYPY from jinja2.exceptions import TemplateNotFound from jinja2.loaders import split_template_path [email protected] class TestLoaders(object): def test_dict_loader(self, dict_loader): env = Environment(loader=dict_loader) @@ -117,8 +115,6 @@ pytest.raises(TemplateNotFound, split_template_path, "../foo") [email protected] [email protected] class TestFileSystemLoader(object): searchpath = os.path.join( os.path.dirname(os.path.abspath(__file__)), "res", "templates" @@ -186,8 +182,6 @@ assert t.render() == expect [email protected] [email protected] class TestModuleLoader(object): archive = None @@ -326,52 +320,3 @@ self.mod_env = Environment(loader=mod_loader) self._test_common() - - [email protected]() -def package_dir_loader(monkeypatch): - monkeypatch.syspath_prepend(os.path.dirname(__file__)) - return PackageLoader("res") - - [email protected]( - ("template", "expect"), [("foo/test.html", "FOO"), ("test.html", "BAR")] -) -def test_package_dir_source(package_dir_loader, template, expect): - source, name, up_to_date = package_dir_loader.get_source(None, template) - assert source.rstrip() == expect - assert name.endswith(os.path.join(*split_template_path(template))) - assert up_to_date() - - -def test_package_dir_list(package_dir_loader): - templates = package_dir_loader.list_templates() - assert "foo/test.html" in templates - assert "test.html" in templates - - [email protected]() -def package_zip_loader(monkeypatch): - monkeypatch.syspath_prepend( - os.path.join(os.path.dirname(__file__), "res", "package.zip") - ) - return PackageLoader("t_pack") - - [email protected]( - ("template", "expect"), [("foo/test.html", "FOO"), ("test.html", "BAR")] -) -def test_package_zip_source(package_zip_loader, template, expect): - source, name, up_to_date = package_zip_loader.get_source(None, template) - assert source.rstrip() == expect - assert name.endswith(os.path.join(*split_template_path(template))) - assert up_to_date is None - - [email protected]( - PYPY, - reason="PyPy's zipimporter doesn't have a _files attribute.", - raises=TypeError, -) -def test_package_zip_list(package_zip_loader): - assert package_zip_loader.list_templates() == ["foo/test.html", "test.html"] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_nativetypes.py new/Jinja2-2.11.2/tests/test_nativetypes.py --- old/Jinja2-2.11.1/tests/test_nativetypes.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_nativetypes.py 2020-04-13 18:11:28.000000000 +0200 @@ -134,6 +134,15 @@ assert result == "--host='localhost' --user \"Jinja\"" +def test_no_intermediate_eval(env): + t = env.from_string("0.000{{ a }}") + result = t.render(a=7) + assert isinstance(result, float) + # If intermediate eval happened, 0.000 would render 0.0, then 7 + # would be appended, resulting in 0.07. + assert result < 0.007 # TODO use math.isclose in Python 3 + + def test_spontaneous_env(): t = NativeTemplate("{{ true }}") assert isinstance(t.environment, NativeEnvironment) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_regression.py new/Jinja2-2.11.2/tests/test_regression.py --- old/Jinja2-2.11.1/tests/test_regression.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_regression.py 2020-04-13 16:18:12.000000000 +0200 @@ -13,7 +13,6 @@ from jinja2._compat import text_type [email protected] class TestCorner(object): def test_assigned_scoping(self, env): t = env.from_string( @@ -85,7 +84,6 @@ assert t.render(wrapper=23) == "[1][2][3][4]23" [email protected] class TestBug(object): def test_keyword_folding(self, env): env = Environment() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_runtime.py new/Jinja2-2.11.2/tests/test_runtime.py --- old/Jinja2-2.11.1/tests/test_runtime.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_runtime.py 2020-04-13 16:18:12.000000000 +0200 @@ -54,3 +54,22 @@ # groupby groups depend on the current position of the iterator. If # it was advanced early, the lists would appear empty. assert out == "1 [(1, 'a'), (1, 'b')]\n2 [(2, 'c')]\n3 [(3, 'd')]\n" + + +def test_mock_not_contextfunction(): + """If a callable class has a ``__getattr__`` that returns True-like + values for arbitrary attrs, it should not be incorrectly identified + as a ``contextfunction``. + """ + + class Calc(object): + def __getattr__(self, item): + return object() + + def __call__(self, *args, **kwargs): + return len(args) + len(kwargs) + + t = Template("{{ calc() }}") + out = t.render(calc=Calc()) + # Would be "1" if context argument was passed. + assert out == "0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_security.py new/Jinja2-2.11.2/tests/test_security.py --- old/Jinja2-2.11.1/tests/test_security.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_security.py 2020-04-13 16:18:12.000000000 +0200 @@ -37,7 +37,6 @@ return "PublicStuff" [email protected] class TestSandbox(object): def test_unsafe(self, env): env = SandboxedEnvironment() @@ -167,7 +166,6 @@ t.render(ctx) [email protected] class TestStringFormat(object): def test_basic_format_safety(self): env = SandboxedEnvironment() @@ -190,7 +188,6 @@ assert t.render() == "a42b<foo>" [email protected] @pytest.mark.skipif( not hasattr(str, "format_map"), reason="requires str.format_map method" ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_tests.py new/Jinja2-2.11.2/tests/test_tests.py --- old/Jinja2-2.11.1/tests/test_tests.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_tests.py 2020-04-13 16:18:12.000000000 +0200 @@ -9,7 +9,6 @@ pass [email protected]_tests class TestTestsCase(object): def test_defined(self, env): tmpl = env.from_string("{{ missing is defined }}|{{ true is defined }}") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Jinja2-2.11.1/tests/test_utils.py new/Jinja2-2.11.2/tests/test_utils.py --- old/Jinja2-2.11.1/tests/test_utils.py 2020-01-29 16:32:24.000000000 +0100 +++ new/Jinja2-2.11.2/tests/test_utils.py 2020-04-13 16:18:12.000000000 +0200 @@ -18,8 +18,6 @@ from jinja2.utils import urlize [email protected] [email protected] class TestLRUCache(object): def test_simple(self): d = LRUCache(3) @@ -120,8 +118,6 @@ assert len(d) == 2 [email protected] [email protected] class TestHelpers(object): def test_object_type_repr(self): class X(object): @@ -150,8 +146,6 @@ assert not func("FOO.TXT") [email protected] [email protected] class TestEscapeUrlizeTarget(object): def test_escape_urlize_target(self): url = "http://example.org" @@ -163,8 +157,6 @@ ) [email protected] [email protected] class TestLoremIpsum(object): def test_lorem_ipsum_markup(self): """Test that output of lorem_ipsum is Markup by default."""
