Skip to content

Commit

Permalink
OpenXR SDK 1.0.34 (2024-02-16)
Browse files Browse the repository at this point in the history
This release features a number of new multi-vendor and vendor
extensions, additional functionality in the reflection header, as well
as compatibility improvements for the loader on Android.

-   Registry
    -   Extension reservation: Register author ID and reserve extensions
        for Leia. (internal MR 3203)
    -   Fix: Remove erroneous interaction profile component additions
        from extensions. (internal MR 3223)
    -   New multi-vendor extension: XR_EXT_user_presence (internal MR
        2706, internal issue 1585)
    -   New vendor extension: XR_META_recommended_layer_resolution
        (internal MR 2570)
    -   New vendor extension: XR_META_automatic_layer_filter (internal
        MR 2696)
    -   New vendor extension: XR_META_spatial_entity_mesh (internal MR
        2773)
    -   New vendor extension: XR_FB_face_tracking2 (internal MR 2811)
    -   New vendor extension: XR_VARJO_xr4_controller_interaction
        (internal MR 3078)
    -   XR_FB_scene: Update to spec version 4. (internal MR 2774)
    -   XR_META_headset_id and XR_FB_spatial_entity: Drop XR_EXT_uuid
        dependency, they use the data structure but do not require any
        runtime support specific to XR_EXT_uuid (internal MR 2577)
-   SDK
    -   API Layers: Add version-script for linking API Layers on Linux
        and Android. (internal MR 3112)
    -   Fix typo in gfxwrapper_opengl that did not affect the use in
        this repository directly, but may affect downstream users of
        this code. (internal MR 3215)
    -   Loader: fix to Android Loader so that the
        /<path_to_apk>/my_apk_file.apk!/libs/libstuff.so will not get
        blocked (internal MR 3054)
    -   Loader: Add missing ifdef guards for XR_KHR_LOADER_INIT_SUPPORT.
        (internal MR 3152, internal MR 3159)
    -   Loader: Fix crash in case of calling
        xrEnumerateInstanceExtensionProperties before calling
        xrInitializeLoaderKHR on Android. (internal MR 3159)
    -   Loader design: Add a note about environment variables being
        ignored when run on Windows as admin. (internal MR 3214)
    -   openxr_reflection.h: Add macros to list functions provided by
        each feature / extension. (internal MR 3129)
    -   external: Update Jinja2 Python module shipped with repository
        (for source code generation) to 2.11.3. (internal MR 3221,
        internal MR 3237)

GitOrigin-RevId: 8e65355a94a5d1b834ba438571cd5cd88c030b22
rpavlik committed Feb 17, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 7696da1 commit 455583c
Showing 66 changed files with 5,098 additions and 3,747 deletions.
2 changes: 1 addition & 1 deletion .appveyor.yml
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@
#
# SPDX-License-Identifier: Apache-2.0

version: 1.0.33.{build}
version: 1.0.34.{build}
image: Visual Studio 2017


2 changes: 1 addition & 1 deletion .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2021-2024, The Khronos Group Inc. Inc.
# Copyright 2021-2024, The Khronos Group Inc.
#
# SPDX-License-Identifier: CC-BY-4.0

2 changes: 1 addition & 1 deletion .reuse/dep5
Original file line number Diff line number Diff line change
@@ -69,7 +69,7 @@ License: MIT
Comment: Unmodified, vendored copy of commit e6c415837c5a487809fdbb2f71f1080d454eb99a

Files: external/python/jinja2/*
external/python/Jinja2-2.10.3.dist-info/*
external/python/Jinja2-2.11.3.dist-info/*
Copyright: 2013-2019 by the Jinja team
2007 Pallets
License: BSD-3-Clause
56 changes: 56 additions & 0 deletions CHANGELOG.SDK.md
Original file line number Diff line number Diff line change
@@ -21,6 +21,62 @@ along with any public pull requests that have been accepted.
In this repository in particular, since it is primarily software,
pull requests may be integrated as they are accepted even between periodic updates.

## OpenXR SDK 1.0.34 (2024-02-16)

This release features a number of new multi-vendor and vendor extensions,
additional functionality in the reflection header, as well as compatibility
improvements for the loader on Android.

- Registry
- Extension reservation: Register author ID and reserve extensions for Leia.
([internal MR 3203](https://gitlab.khronos.org/openxr/openxr/merge_requests/3203))
- Fix: Remove erroneous interaction profile component additions from extensions.
([internal MR 3223](https://gitlab.khronos.org/openxr/openxr/merge_requests/3223))
- New multi-vendor extension: `XR_EXT_user_presence`
([internal MR 2706](https://gitlab.khronos.org/openxr/openxr/merge_requests/2706),
[internal issue 1585](https://gitlab.khronos.org/openxr/openxr/issues/1585))
- New vendor extension: `XR_META_recommended_layer_resolution`
([internal MR 2570](https://gitlab.khronos.org/openxr/openxr/merge_requests/2570))
- New vendor extension: `XR_META_automatic_layer_filter`
([internal MR 2696](https://gitlab.khronos.org/openxr/openxr/merge_requests/2696))
- New vendor extension: `XR_META_spatial_entity_mesh`
([internal MR 2773](https://gitlab.khronos.org/openxr/openxr/merge_requests/2773))
- New vendor extension: `XR_FB_face_tracking2`
([internal MR 2811](https://gitlab.khronos.org/openxr/openxr/merge_requests/2811))
- New vendor extension: `XR_VARJO_xr4_controller_interaction`
([internal MR 3078](https://gitlab.khronos.org/openxr/openxr/merge_requests/3078))
- `XR_FB_scene`: Update to spec version 4.
([internal MR 2774](https://gitlab.khronos.org/openxr/openxr/merge_requests/2774))
- `XR_META_headset_id` and `XR_FB_spatial_entity`: Drop `XR_EXT_uuid` dependency,
they use the data structure but do not require any runtime support specific to
`XR_EXT_uuid`
([internal MR 2577](https://gitlab.khronos.org/openxr/openxr/merge_requests/2577))
- SDK
- API Layers: Add version-script for linking API Layers on Linux and Android.
([internal MR 3112](https://gitlab.khronos.org/openxr/openxr/merge_requests/3112))
- Fix typo in `gfxwrapper_opengl` that did not affect the use in this repository
directly, but may affect downstream users of this code.
([internal MR 3215](https://gitlab.khronos.org/openxr/openxr/merge_requests/3215))
- Loader: fix to Android Loader so that the
`/<path_to_apk>/my_apk_file.apk!/libs/libstuff.so` will not get blocked
([internal MR 3054](https://gitlab.khronos.org/openxr/openxr/merge_requests/3054))
- Loader: Add missing ifdef guards for `XR_KHR_LOADER_INIT_SUPPORT`.
([internal MR 3152](https://gitlab.khronos.org/openxr/openxr/merge_requests/3152),
[internal MR 3159](https://gitlab.khronos.org/openxr/openxr/merge_requests/3159))
- Loader: Fix crash in case of calling `xrEnumerateInstanceExtensionProperties`
before calling `xrInitializeLoaderKHR` on Android.
([internal MR 3159](https://gitlab.khronos.org/openxr/openxr/merge_requests/3159))
- Loader design: Add a note about environment variables being ignored when run on
Windows as admin.
([internal MR 3214](https://gitlab.khronos.org/openxr/openxr/merge_requests/3214))
- `openxr_reflection.h`: Add macros to list functions provided by each feature /
extension.
([internal MR 3129](https://gitlab.khronos.org/openxr/openxr/merge_requests/3129))
- external: Update Jinja2 Python module shipped with repository (for source code
generation) to 2.11.3.
([internal MR 3221](https://gitlab.khronos.org/openxr/openxr/merge_requests/3221),
[internal MR 3237](https://gitlab.khronos.org/openxr/openxr/merge_requests/3237))

## OpenXR SDK 1.0.33 (2024-01-03)

This release primarily adds new ratified functionality describing the loader
62 changes: 0 additions & 62 deletions external/python/Jinja2-2.10.3.dist-info/RECORD

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: Jinja2
Version: 2.10.3
Version: 2.11.3
Summary: A very fast and expressive template engine.
Home-page: https://palletsprojects.com/p/jinja/
Author: Armin Ronacher
@@ -24,11 +24,14 @@ Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Text Processing :: Markup :: HTML
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
Description-Content-Type: text/x-rst
Requires-Dist: MarkupSafe (>=0.23)
Provides-Extra: i18n
Requires-Dist: Babel (>=0.8) ; extra == 'i18n'
35 changes: 35 additions & 0 deletions external/python/Jinja2-2.11.3.dist-info/RECORD
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
Jinja2-2.11.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Jinja2-2.11.3.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
Jinja2-2.11.3.dist-info/METADATA,sha256=PscpJ1C3RSp8xcjV3fAuTz13rKbGxmzJXnMQFH-WKhs,3535
Jinja2-2.11.3.dist-info/RECORD,,
Jinja2-2.11.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
Jinja2-2.11.3.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110
Jinja2-2.11.3.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61
Jinja2-2.11.3.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
jinja2/__init__.py,sha256=LZUXmxJc2GIchfSAeMWsxCWiQYO-w1-736f2Q3I8ms8,1549
jinja2/_compat.py,sha256=B6Se8HjnXVpzz9-vfHejn-DV2NjaVK-Iewupc5kKlu8,3191
jinja2/_identifier.py,sha256=EdgGJKi7O1yvr4yFlvqPNEqV6M1qHyQr8Gt8GmVTKVM,1775
jinja2/asyncfilters.py,sha256=XJtYXTxFvcJ5xwk6SaDL4S0oNnT0wPYvXBCSzc482fI,4250
jinja2/asyncsupport.py,sha256=ZBFsDLuq3Gtji3Ia87lcyuDbqaHZJRdtShZcqwpFnSQ,7209
jinja2/bccache.py,sha256=3Pmp4jo65M9FQuIxdxoDBbEDFwe4acDMQf77nEJfrHA,12139
jinja2/compiler.py,sha256=Ta9W1Lit542wItAHXlDcg0sEOsFDMirCdlFPHAurg4o,66284
jinja2/constants.py,sha256=RR1sTzNzUmKco6aZicw4JpQpJGCuPuqm1h1YmCNUEFY,1458
jinja2/debug.py,sha256=neR7GIGGjZH3_ILJGVUYy3eLQCCaWJMXOb7o0kGInWc,8529
jinja2/defaults.py,sha256=85B6YUUCyWPSdrSeVhcqFVuu_bHUAQXeey--FIwSeVQ,1126
jinja2/environment.py,sha256=XDSLKc4SqNLMOwTSq3TbWEyA5WyXfuLuVD0wAVjEFwM,50629
jinja2/exceptions.py,sha256=VjNLawcmf2ODffqVMCQK1cRmvFaUfQWF4u8ouP3QPcE,5425
jinja2/ext.py,sha256=AtwL5O5enT_L3HR9-oBvhGyUTdGoyaqG_ICtnR_EVd4,26441
jinja2/filters.py,sha256=9ORilsZrUoydSI9upz8_qGy7gozDWLYoFmlIBFSVRnQ,41439
jinja2/idtracking.py,sha256=J3O4VHsrbf3wzwiBc7Cro26kHb6_5kbULeIOzocchIU,9211
jinja2/lexer.py,sha256=nUFLRKhhKmmEWkLI65nQePgcQs7qsRdjVYZETMt_v0g,30331
jinja2/loaders.py,sha256=C-fST_dmFjgWkp0ZuCkrgICAoOsoSIF28wfAFink0oU,17666
jinja2/meta.py,sha256=QjyYhfNRD3QCXjBJpiPl9KgkEkGXJbAkCUq4-Ur10EQ,4131
jinja2/nativetypes.py,sha256=Ul__gtVw4xH-0qvUvnCNHedQeNDwmEuyLJztzzSPeRg,2753
jinja2/nodes.py,sha256=Mk1oJPVgIjnQw9WOqILvcu3rLepcFZ0ahxQm2mbwDwc,31095
jinja2/optimizer.py,sha256=gQLlMYzvQhluhzmAIFA1tXS0cwgWYOjprN-gTRcHVsc,1457
jinja2/parser.py,sha256=fcfdqePNTNyvosIvczbytVA332qpsURvYnCGcjDHSkA,35660
jinja2/runtime.py,sha256=0y-BRyIEZ9ltByL2Id6GpHe1oDRQAwNeQvI0SKobNMw,30618
jinja2/sandbox.py,sha256=knayyUvXsZ-F0mk15mO2-ehK9gsw04UhB8td-iUOtLc,17127
jinja2/tests.py,sha256=iO_Y-9Vo60zrVe1lMpSl5sKHqAxe2leZHC08OoZ8K24,4799
jinja2/utils.py,sha256=Wy4yC3IByqUWwnKln6SdaixdzgK74P6F5nf-gQZrYnU,22436
jinja2/visitor.py,sha256=DUHupl0a4PGp7nxRtZFttUzAi1ccxzqc2hzetPYUz8U,3240
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.33.6)
Generator: bdist_wheel (0.36.2)
Root-Is-Purelib: true
Tag: py2-none-any
Tag: py3-none-any
123 changes: 42 additions & 81 deletions external/python/jinja2/__init__.py
Original file line number Diff line number Diff line change
@@ -1,83 +1,44 @@
# -*- coding: utf-8 -*-
"""Jinja is a template engine written in pure Python. It provides a
non-XML syntax that supports inline expressions and an optional
sandboxed environment.
"""
jinja2
~~~~~~
Jinja2 is a template engine written in pure Python. It provides a
Django inspired non-XML syntax but supports inline expressions and
an optional sandboxed environment.
Nutshell
--------
Here a small example of a Jinja2 template::
{% extends 'base.html' %}
{% block title %}Memberlist{% endblock %}
{% block content %}
<ul>
{% for user in users %}
<li><a href="{{ user.url }}">{{ user.username }}</a></li>
{% endfor %}
</ul>
{% endblock %}
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
__docformat__ = 'restructuredtext en'
__version__ = "2.10.3"

# high level interface
from jinja2.environment import Environment, Template

# loaders
from jinja2.loaders import BaseLoader, FileSystemLoader, PackageLoader, \
DictLoader, FunctionLoader, PrefixLoader, ChoiceLoader, \
ModuleLoader

# bytecode caches
from jinja2.bccache import BytecodeCache, FileSystemBytecodeCache, \
MemcachedBytecodeCache

# undefined types
from jinja2.runtime import Undefined, DebugUndefined, StrictUndefined, \
make_logging_undefined

# exceptions
from jinja2.exceptions import TemplateError, UndefinedError, \
TemplateNotFound, TemplatesNotFound, TemplateSyntaxError, \
TemplateAssertionError, TemplateRuntimeError

# decorators and public utilities
from jinja2.filters import environmentfilter, contextfilter, \
evalcontextfilter
from jinja2.utils import Markup, escape, clear_caches, \
environmentfunction, evalcontextfunction, contextfunction, \
is_undefined, select_autoescape

__all__ = [
'Environment', 'Template', 'BaseLoader', 'FileSystemLoader',
'PackageLoader', 'DictLoader', 'FunctionLoader', 'PrefixLoader',
'ChoiceLoader', 'BytecodeCache', 'FileSystemBytecodeCache',
'MemcachedBytecodeCache', 'Undefined', 'DebugUndefined',
'StrictUndefined', 'TemplateError', 'UndefinedError', 'TemplateNotFound',
'TemplatesNotFound', 'TemplateSyntaxError', 'TemplateAssertionError',
'TemplateRuntimeError',
'ModuleLoader', 'environmentfilter', 'contextfilter', 'Markup', 'escape',
'environmentfunction', 'contextfunction', 'clear_caches', 'is_undefined',
'evalcontextfilter', 'evalcontextfunction', 'make_logging_undefined',
'select_autoescape',
]


def _patch_async():
from jinja2.utils import have_async_gen
if have_async_gen:
from jinja2.asyncsupport import patch_all
patch_all()


_patch_async()
del _patch_async
from markupsafe import escape
from markupsafe import Markup

from .bccache import BytecodeCache
from .bccache import FileSystemBytecodeCache
from .bccache import MemcachedBytecodeCache
from .environment import Environment
from .environment import Template
from .exceptions import TemplateAssertionError
from .exceptions import TemplateError
from .exceptions import TemplateNotFound
from .exceptions import TemplateRuntimeError
from .exceptions import TemplatesNotFound
from .exceptions import TemplateSyntaxError
from .exceptions import UndefinedError
from .filters import contextfilter
from .filters import environmentfilter
from .filters import evalcontextfilter
from .loaders import BaseLoader
from .loaders import ChoiceLoader
from .loaders import DictLoader
from .loaders import FileSystemLoader
from .loaders import FunctionLoader
from .loaders import ModuleLoader
from .loaders import PackageLoader
from .loaders import PrefixLoader
from .runtime import ChainableUndefined
from .runtime import DebugUndefined
from .runtime import make_logging_undefined
from .runtime import StrictUndefined
from .runtime import Undefined
from .utils import clear_caches
from .utils import contextfunction
from .utils import environmentfunction
from .utils import evalcontextfunction
from .utils import is_undefined
from .utils import select_autoescape

__version__ = "2.11.3"
61 changes: 44 additions & 17 deletions external/python/jinja2/_compat.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,12 @@
# -*- coding: utf-8 -*-
"""
jinja2._compat
~~~~~~~~~~~~~~
Some py2/py3 compatibility support based on a stripped down
version of six so we don't have to depend on a specific version
of it.
:copyright: Copyright 2013 by the Jinja team, see AUTHORS.
:license: BSD, see LICENSE for details.
"""
# flake8: noqa
import marshal
import sys

PY2 = sys.version_info[0] == 2
PYPY = hasattr(sys, 'pypy_translation_info')
PYPY = hasattr(sys, "pypy_translation_info")
_identity = lambda x: x


if not PY2:
unichr = chr
range_type = range
@@ -30,6 +20,7 @@

import pickle
from io import BytesIO, StringIO

NativeStringIO = StringIO

def reraise(tp, value, tb=None):
@@ -46,6 +37,9 @@ def reraise(tp, value, tb=None):
implements_to_string = _identity
encode_filename = _identity

marshal_dump = marshal.dump
marshal_load = marshal.load

else:
unichr = unichr
text_type = unicode
@@ -59,11 +53,13 @@ def reraise(tp, value, tb=None):

import cPickle as pickle
from cStringIO import StringIO as BytesIO, StringIO

NativeStringIO = BytesIO

exec('def reraise(tp, value, tb=None):\n raise tp, value, tb')
exec("def reraise(tp, value, tb=None):\n raise tp, value, tb")

from itertools import imap, izip, ifilter

intern = intern

def implements_iterator(cls):
@@ -73,14 +69,25 @@ def implements_iterator(cls):

def implements_to_string(cls):
cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode('utf-8')
cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
return cls

def encode_filename(filename):
if isinstance(filename, unicode):
return filename.encode('utf-8')
return filename.encode("utf-8")
return filename

def marshal_dump(code, f):
if isinstance(f, file):
marshal.dump(code, f)
else:
f.write(marshal.dumps(code))

def marshal_load(f):
if isinstance(f, file):
return marshal.load(f)
return marshal.loads(f.read())


def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
@@ -90,7 +97,8 @@ def with_metaclass(meta, *bases):
class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, 'temporary_class', (), {})

return type.__new__(metaclass, "temporary_class", (), {})


try:
@@ -103,3 +111,22 @@ def __new__(cls, name, this_bases, d):
from collections import abc
except ImportError:
import collections as abc


try:
from os import fspath
except ImportError:
try:
from pathlib import PurePath
except ImportError:
PurePath = None

def fspath(path):
if hasattr(path, "__fspath__"):
return path.__fspath__()

# Python 3.5 doesn't have __fspath__ yet, use str.
if PurePath is not None and isinstance(path, PurePath):
return str(path)

return path
6 changes: 5 additions & 1 deletion external/python/jinja2/_identifier.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
import re

# generated by scripts/generate_identifier_pattern.py
pattern = '·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯'
pattern = re.compile(
r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣔ-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఃా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑅳𑄴𑆀-𑆂𑆳-𑇊𑇀-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950
)
70 changes: 41 additions & 29 deletions external/python/jinja2/asyncfilters.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
from functools import wraps

from jinja2.asyncsupport import auto_aiter
from jinja2 import filters
from . import filters
from .asyncsupport import auto_aiter
from .asyncsupport import auto_await


async def auto_to_seq(value):
seq = []
if hasattr(value, '__aiter__'):
if hasattr(value, "__aiter__"):
async for item in value:
seq.append(item)
else:
@@ -16,8 +17,7 @@ async def auto_to_seq(value):


async def async_select_or_reject(args, kwargs, modfunc, lookup_attr):
seq, func = filters.prepare_select_or_reject(
args, kwargs, modfunc, lookup_attr)
seq, func = filters.prepare_select_or_reject(args, kwargs, modfunc, lookup_attr)
if seq:
async for item in auto_aiter(seq):
if func(item):
@@ -26,14 +26,19 @@ async def async_select_or_reject(args, kwargs, modfunc, lookup_attr):

def dualfilter(normal_filter, async_filter):
wrap_evalctx = False
if getattr(normal_filter, 'environmentfilter', False):
is_async = lambda args: args[0].is_async
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
is_async = lambda args: args[0].environment.is_async
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

@wraps(normal_filter)
def wrapper(*args, **kwargs):
@@ -55,6 +60,7 @@ def wrapper(*args, **kwargs):
def asyncfiltervariant(original):
def decorator(f):
return dualfilter(original, f)

return decorator


@@ -63,19 +69,22 @@ async def do_first(environment, seq):
try:
return await auto_aiter(seq).__anext__()
except StopAsyncIteration:
return environment.undefined('No first item, sequence was empty.')
return environment.undefined("No first item, sequence was empty.")


@asyncfiltervariant(filters.do_groupby)
async def do_groupby(environment, value, attribute):
expr = filters.make_attrgetter(environment, attribute)
return [filters._GroupTuple(key, await auto_to_seq(values))
for key, values in filters.groupby(sorted(
await auto_to_seq(value), key=expr), expr)]
return [
filters._GroupTuple(key, await auto_to_seq(values))
for key, values in filters.groupby(
sorted(await auto_to_seq(value), key=expr), expr
)
]


@asyncfiltervariant(filters.do_join)
async def do_join(eval_ctx, value, d=u'', attribute=None):
async def do_join(eval_ctx, value, d=u"", attribute=None):
return filters.do_join(eval_ctx, await auto_to_seq(value), d, attribute)


@@ -109,7 +118,7 @@ async def do_map(*args, **kwargs):
seq, func = filters.prepare_map(args, kwargs)
if seq:
async for item in auto_aiter(seq):
yield func(item)
yield await auto_await(func(item))


@asyncfiltervariant(filters.do_sum)
@@ -118,7 +127,10 @@ async def do_sum(environment, iterable, attribute=None, start=0):
if attribute is not None:
func = filters.make_attrgetter(environment, attribute)
else:
func = lambda x: x

def func(x):
return x

async for item in auto_aiter(iterable):
rv += func(item)
return rv
@@ -130,17 +142,17 @@ async def do_slice(value, slices, fill_with=None):


ASYNC_FILTERS = {
'first': do_first,
'groupby': do_groupby,
'join': do_join,
'list': do_list,
"first": do_first,
"groupby": do_groupby,
"join": do_join,
"list": do_list,
# we intentionally do not support do_last because that would be
# ridiculous
'reject': do_reject,
'rejectattr': do_rejectattr,
'map': do_map,
'select': do_select,
'selectattr': do_selectattr,
'sum': do_sum,
'slice': do_slice,
"reject": do_reject,
"rejectattr": do_rejectattr,
"map": do_map,
"select": do_select,
"selectattr": do_selectattr,
"sum": do_sum,
"slice": do_slice,
}
186 changes: 97 additions & 89 deletions external/python/jinja2/asyncsupport.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,27 @@
# -*- coding: utf-8 -*-
"""The code for async support. Importing this patches Jinja on supported
Python versions.
"""
jinja2.asyncsupport
~~~~~~~~~~~~~~~~~~~
Has all the code for async support which is implemented as a patch
for supported Python versions.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
import sys
import asyncio
import inspect
from functools import update_wrapper

from jinja2.utils import concat, internalcode, Markup
from jinja2.environment import TemplateModule
from jinja2.runtime import LoopContextBase, _last_iteration
from markupsafe import Markup

from .environment import TemplateModule
from .runtime import LoopContext
from .utils import concat
from .utils import internalcode
from .utils import missing


async def concat_async(async_gen):
rv = []

async def collect():
async for event in async_gen:
rv.append(event)

await collect()
return concat(rv)

@@ -34,10 +32,7 @@ async def generate_async(self, *args, **kwargs):
async for event in self.root_render_func(self.new_context(vars)):
yield event
except Exception:
exc_info = sys.exc_info()
else:
return
yield self.environment.handle_exception(exc_info, True)
yield self.environment.handle_exception()


def wrap_generate_func(original_generate):
@@ -48,26 +43,26 @@ def _convert_generator(self, loop, args, kwargs):
yield loop.run_until_complete(async_gen.__anext__())
except StopAsyncIteration:
pass

def generate(self, *args, **kwargs):
if not self.environment.is_async:
return original_generate(self, *args, **kwargs)
return _convert_generator(self, asyncio.get_event_loop(), args, kwargs)

return update_wrapper(generate, original_generate)


async def render_async(self, *args, **kwargs):
if not self.environment.is_async:
raise RuntimeError('The environment was not created with async mode '
'enabled.')
raise RuntimeError("The environment was not created with async mode enabled.")

vars = dict(*args, **kwargs)
ctx = self.new_context(vars)

try:
return await concat_async(self.root_render_func(ctx))
except Exception:
exc_info = sys.exc_info()
return self.environment.handle_exception(exc_info, True)
return self.environment.handle_exception()


def wrap_render_func(original_render):
@@ -76,6 +71,7 @@ def render(self, *args, **kwargs):
return original_render(self, *args, **kwargs)
loop = asyncio.get_event_loop()
return loop.run_until_complete(self.render_async(*args, **kwargs))

return update_wrapper(render, original_render)


@@ -109,6 +105,7 @@ def _invoke(self, arguments, autoescape):
if not self._environment.is_async:
return original_invoke(self, arguments, autoescape)
return async_invoke(self, arguments, autoescape)

return update_wrapper(_invoke, original_invoke)


@@ -124,9 +121,9 @@ def wrap_default_module(original_default_module):
@internalcode
def _get_default_module(self):
if self.environment.is_async:
raise RuntimeError('Template module attribute is unavailable '
'in async mode')
raise RuntimeError("Template module attribute is unavailable in async mode")
return original_default_module(self)

return _get_default_module


@@ -139,30 +136,30 @@ async def make_module_async(self, vars=None, shared=False, locals=None):


def patch_template():
from jinja2 import Template
from . import Template

Template.generate = wrap_generate_func(Template.generate)
Template.generate_async = update_wrapper(
generate_async, Template.generate_async)
Template.render_async = update_wrapper(
render_async, Template.render_async)
Template.generate_async = update_wrapper(generate_async, Template.generate_async)
Template.render_async = update_wrapper(render_async, Template.render_async)
Template.render = wrap_render_func(Template.render)
Template._get_default_module = wrap_default_module(
Template._get_default_module)
Template._get_default_module = wrap_default_module(Template._get_default_module)
Template._get_default_module_async = get_default_module_async
Template.make_module_async = update_wrapper(
make_module_async, Template.make_module_async)
make_module_async, Template.make_module_async
)


def patch_runtime():
from jinja2.runtime import BlockReference, Macro
BlockReference.__call__ = wrap_block_reference_call(
BlockReference.__call__)
from .runtime import BlockReference, Macro

BlockReference.__call__ = wrap_block_reference_call(BlockReference.__call__)
Macro._invoke = wrap_macro_invoke(Macro._invoke)


def patch_filters():
from jinja2.filters import FILTERS
from jinja2.asyncfilters import ASYNC_FILTERS
from .filters import FILTERS
from .asyncfilters import ASYNC_FILTERS

FILTERS.update(ASYNC_FILTERS)


@@ -179,78 +176,89 @@ async def auto_await(value):


async def auto_aiter(iterable):
if hasattr(iterable, '__aiter__'):
if hasattr(iterable, "__aiter__"):
async for item in iterable:
yield item
return
for item in iterable:
yield item


class AsyncLoopContext(LoopContextBase):

def __init__(self, async_iterator, undefined, after, length, recurse=None,
depth0=0):
LoopContextBase.__init__(self, undefined, recurse, depth0)
self._async_iterator = async_iterator
self._after = after
self._length = length
class AsyncLoopContext(LoopContext):
_to_iterator = staticmethod(auto_aiter)

@property
def length(self):
if self._length is None:
raise TypeError('Loop length for some iterators cannot be '
'lazily calculated in async mode')
async def length(self):
if self._length is not None:
return self._length

try:
self._length = len(self._iterable)
except TypeError:
iterable = [x async for x in self._iterator]
self._iterator = self._to_iterator(iterable)
self._length = len(iterable) + self.index + (self._after is not missing)

return self._length

def __aiter__(self):
return AsyncLoopContextIterator(self)
@property
async def revindex0(self):
return await self.length - self.index

@property
async def revindex(self):
return await self.length - self.index0

async def _peek_next(self):
if self._after is not missing:
return self._after

try:
self._after = await self._iterator.__anext__()
except StopAsyncIteration:
self._after = missing

class AsyncLoopContextIterator(object):
__slots__ = ('context',)
return self._after

def __init__(self, context):
self.context = context
@property
async def last(self):
return await self._peek_next() is missing

@property
async def nextitem(self):
rv = await self._peek_next()

if rv is missing:
return self._undefined("there is no next item")

return rv

def __aiter__(self):
return self

async def __anext__(self):
ctx = self.context
ctx.index0 += 1
if ctx._after is _last_iteration:
raise StopAsyncIteration()
ctx._before = ctx._current
ctx._current = ctx._after
try:
ctx._after = await ctx._async_iterator.__anext__()
except StopAsyncIteration:
ctx._after = _last_iteration
return ctx._current, ctx
if self._after is not missing:
rv = self._after
self._after = missing
else:
rv = await self._iterator.__anext__()

self.index0 += 1
self._before = self._current
self._current = rv
return rv, self


async def make_async_loop_context(iterable, undefined, recurse=None, depth0=0):
# Length is more complicated and less efficient in async mode. The
# reason for this is that we cannot know if length will be used
# upfront but because length is a property we cannot lazily execute it
# later. This means that we need to buffer it up and measure :(
#
# We however only do this for actual iterators, not for async
# iterators as blocking here does not seem like the best idea in the
# world.
try:
length = len(iterable)
except (TypeError, AttributeError):
if not hasattr(iterable, '__aiter__'):
iterable = tuple(iterable)
length = len(iterable)
else:
length = None
async_iterator = auto_aiter(iterable)
try:
after = await async_iterator.__anext__()
except StopAsyncIteration:
after = _last_iteration
return AsyncLoopContext(async_iterator, undefined, after, length, recurse,
depth0)
import warnings

warnings.warn(
"This template must be recompiled with at least Jinja 2.11, or"
" it will fail in 3.0.",
DeprecationWarning,
stacklevel=2,
)
return AsyncLoopContext(iterable, undefined, recurse, depth0)


patch_all()
137 changes: 63 additions & 74 deletions external/python/jinja2/bccache.py
Original file line number Diff line number Diff line change
@@ -1,60 +1,37 @@
# -*- coding: utf-8 -*-
"""
jinja2.bccache
~~~~~~~~~~~~~~
This module implements the bytecode cache system Jinja is optionally
using. This is useful if you have very complex template situations and
the compiliation of all those templates slow down your application too
much.
Situations where this is useful are often forking web applications that
are initialized on the first request.
"""The optional bytecode cache system. This is useful if you have very
complex template situations and the compilation of all those templates
slows down your application too much.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD.
Situations where this is useful are often forking web applications that
are initialized on the first request.
"""
from os import path, listdir
import errno
import fnmatch
import os
import sys
import stat
import errno
import marshal
import sys
import tempfile
import fnmatch
from hashlib import sha1
from jinja2.utils import open_if_exists
from jinja2._compat import BytesIO, pickle, PY2, text_type


# marshal works better on 3.x, one hack less required
if not PY2:
marshal_dump = marshal.dump
marshal_load = marshal.load
else:

def marshal_dump(code, f):
if isinstance(f, file):
marshal.dump(code, f)
else:
f.write(marshal.dumps(code))

def marshal_load(f):
if isinstance(f, file):
return marshal.load(f)
return marshal.loads(f.read())


bc_version = 3

# magic version used to only change with new jinja versions. With 2.6
# we change this to also take Python version changes into account. The
# reason for this is that Python tends to segfault if fed earlier bytecode
# versions because someone thought it would be a good idea to reuse opcodes
# or make Python incompatible with earlier versions.
bc_magic = 'j2'.encode('ascii') + \
pickle.dumps(bc_version, 2) + \
pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1])
from os import listdir
from os import path

from ._compat import BytesIO
from ._compat import marshal_dump
from ._compat import marshal_load
from ._compat import pickle
from ._compat import text_type
from .utils import open_if_exists

bc_version = 4
# Magic bytes to identify Jinja bytecode cache files. Contains the
# Python major and minor version to avoid loading incompatible bytecode
# if a project upgrades its Python version.
bc_magic = (
b"j2"
+ pickle.dumps(bc_version, 2)
+ pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2)
)


class Bucket(object):
@@ -98,7 +75,7 @@ def load_bytecode(self, f):
def write_bytecode(self, f):
"""Dump the bytecode into the file or file like object passed."""
if self.code is None:
raise TypeError('can\'t write empty bucket')
raise TypeError("can't write empty bucket")
f.write(bc_magic)
pickle.dump(self.checksum, f, 2)
marshal_dump(self.code, f)
@@ -140,7 +117,7 @@ def dump_bytecode(self, bucket):
bucket.write_bytecode(f)
A more advanced version of a filesystem based bytecode cache is part of
Jinja2.
Jinja.
"""

def load_bytecode(self, bucket):
@@ -158,24 +135,24 @@ def dump_bytecode(self, bucket):
raise NotImplementedError()

def clear(self):
"""Clears the cache. This method is not used by Jinja2 but should be
"""Clears the cache. This method is not used by Jinja but should be
implemented to allow applications to clear the bytecode cache used
by a particular environment.
"""

def get_cache_key(self, name, filename=None):
"""Returns the unique hash key for this template name."""
hash = sha1(name.encode('utf-8'))
hash = sha1(name.encode("utf-8"))
if filename is not None:
filename = '|' + filename
filename = "|" + filename
if isinstance(filename, text_type):
filename = filename.encode('utf-8')
filename = filename.encode("utf-8")
hash.update(filename)
return hash.hexdigest()

def get_source_checksum(self, source):
"""Returns a checksum for the source."""
return sha1(source.encode('utf-8')).hexdigest()
return sha1(source.encode("utf-8")).hexdigest()

def get_bucket(self, environment, name, filename, source):
"""Return a cache bucket for the given template. All arguments are
@@ -210,27 +187,29 @@ class FileSystemBytecodeCache(BytecodeCache):
This bytecode cache supports clearing of the cache using the clear method.
"""

def __init__(self, directory=None, pattern='__jinja2_%s.cache'):
def __init__(self, directory=None, pattern="__jinja2_%s.cache"):
if directory is None:
directory = self._get_default_cache_dir()
self.directory = directory
self.pattern = pattern

def _get_default_cache_dir(self):
def _unsafe_dir():
raise RuntimeError('Cannot determine safe temp directory. You '
'need to explicitly provide one.')
raise RuntimeError(
"Cannot determine safe temp directory. You "
"need to explicitly provide one."
)

tmpdir = tempfile.gettempdir()

# On windows the temporary directory is used specific unless
# explicitly forced otherwise. We can just use that.
if os.name == 'nt':
if os.name == "nt":
return tmpdir
if not hasattr(os, 'getuid'):
if not hasattr(os, "getuid"):
_unsafe_dir()

dirname = '_jinja2-cache-%d' % os.getuid()
dirname = "_jinja2-cache-%d" % os.getuid()
actual_dir = os.path.join(tmpdir, dirname)

try:
@@ -241,18 +220,22 @@ def _unsafe_dir():
try:
os.chmod(actual_dir, stat.S_IRWXU)
actual_dir_stat = os.lstat(actual_dir)
if actual_dir_stat.st_uid != os.getuid() \
or not stat.S_ISDIR(actual_dir_stat.st_mode) \
or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU:
if (
actual_dir_stat.st_uid != os.getuid()
or not stat.S_ISDIR(actual_dir_stat.st_mode)
or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU
):
_unsafe_dir()
except OSError as e:
if e.errno != errno.EEXIST:
raise

actual_dir_stat = os.lstat(actual_dir)
if actual_dir_stat.st_uid != os.getuid() \
or not stat.S_ISDIR(actual_dir_stat.st_mode) \
or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU:
if (
actual_dir_stat.st_uid != os.getuid()
or not stat.S_ISDIR(actual_dir_stat.st_mode)
or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU
):
_unsafe_dir()

return actual_dir
@@ -261,15 +244,15 @@ def _get_cache_filename(self, bucket):
return path.join(self.directory, self.pattern % bucket.key)

def load_bytecode(self, bucket):
f = open_if_exists(self._get_cache_filename(bucket), 'rb')
f = open_if_exists(self._get_cache_filename(bucket), "rb")
if f is not None:
try:
bucket.load_bytecode(f)
finally:
f.close()

def dump_bytecode(self, bucket):
f = open(self._get_cache_filename(bucket), 'wb')
f = open(self._get_cache_filename(bucket), "wb")
try:
bucket.write_bytecode(f)
finally:
@@ -280,7 +263,8 @@ def clear(self):
# write access on the file system and the function does not exist
# normally.
from os import remove
files = fnmatch.filter(listdir(self.directory), self.pattern % '*')

files = fnmatch.filter(listdir(self.directory), self.pattern % "*")
for filename in files:
try:
remove(path.join(self.directory, filename))
@@ -333,8 +317,13 @@ class MemcachedBytecodeCache(BytecodeCache):
`ignore_memcache_errors` parameter.
"""

def __init__(self, client, prefix='jinja2/bytecode/', timeout=None,
ignore_memcache_errors=True):
def __init__(
self,
client,
prefix="jinja2/bytecode/",
timeout=None,
ignore_memcache_errors=True,
):
self.client = client
self.prefix = prefix
self.timeout = timeout
1,242 changes: 682 additions & 560 deletions external/python/jinja2/compiler.py

Large diffs are not rendered by default.

15 changes: 2 additions & 13 deletions external/python/jinja2/constants.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,6 @@
# -*- coding: utf-8 -*-
"""
jinja.constants
~~~~~~~~~~~~~~~
Various constants.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""


#: list of lorem ipsum words used by the lipsum() helper function
LOREM_IPSUM_WORDS = u'''\
LOREM_IPSUM_WORDS = u"""\
a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at
auctor augue bibendum blandit class commodo condimentum congue consectetuer
consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus
@@ -29,4 +18,4 @@
sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor
tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices
ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus
viverra volutpat vulputate'''
viverra volutpat vulputate"""
528 changes: 209 additions & 319 deletions external/python/jinja2/debug.py

Large diffs are not rendered by default.

68 changes: 28 additions & 40 deletions external/python/jinja2/defaults.py
Original file line number Diff line number Diff line change
@@ -1,56 +1,44 @@
# -*- coding: utf-8 -*-
"""
jinja2.defaults
~~~~~~~~~~~~~~~
Jinja default filters and tags.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
from jinja2._compat import range_type
from jinja2.utils import generate_lorem_ipsum, Cycler, Joiner, Namespace

from ._compat import range_type
from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401
from .tests import TESTS as DEFAULT_TESTS # noqa: F401
from .utils import Cycler
from .utils import generate_lorem_ipsum
from .utils import Joiner
from .utils import Namespace

# defaults for the parser / lexer
BLOCK_START_STRING = '{%'
BLOCK_END_STRING = '%}'
VARIABLE_START_STRING = '{{'
VARIABLE_END_STRING = '}}'
COMMENT_START_STRING = '{#'
COMMENT_END_STRING = '#}'
BLOCK_START_STRING = "{%"
BLOCK_END_STRING = "%}"
VARIABLE_START_STRING = "{{"
VARIABLE_END_STRING = "}}"
COMMENT_START_STRING = "{#"
COMMENT_END_STRING = "#}"
LINE_STATEMENT_PREFIX = None
LINE_COMMENT_PREFIX = None
TRIM_BLOCKS = False
LSTRIP_BLOCKS = False
NEWLINE_SEQUENCE = '\n'
NEWLINE_SEQUENCE = "\n"
KEEP_TRAILING_NEWLINE = False


# default filters, tests and namespace
from jinja2.filters import FILTERS as DEFAULT_FILTERS
from jinja2.tests import TESTS as DEFAULT_TESTS

DEFAULT_NAMESPACE = {
'range': range_type,
'dict': dict,
'lipsum': generate_lorem_ipsum,
'cycler': Cycler,
'joiner': Joiner,
'namespace': Namespace
"range": range_type,
"dict": dict,
"lipsum": generate_lorem_ipsum,
"cycler": Cycler,
"joiner": Joiner,
"namespace": Namespace,
}


# default policies
DEFAULT_POLICIES = {
'compiler.ascii_str': True,
'urlize.rel': 'noopener',
'urlize.target': None,
'truncate.leeway': 5,
'json.dumps_function': None,
'json.dumps_kwargs': {'sort_keys': True},
'ext.i18n.trimmed': False,
"compiler.ascii_str": True,
"urlize.rel": "noopener",
"urlize.target": None,
"truncate.leeway": 5,
"json.dumps_function": None,
"json.dumps_kwargs": {"sort_keys": True},
"ext.i18n.trimmed": False,
}


# export all constants
__all__ = tuple(x for x in locals().keys() if x.isupper())
592 changes: 339 additions & 253 deletions external/python/jinja2/environment.py

Large diffs are not rendered by default.

73 changes: 52 additions & 21 deletions external/python/jinja2/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,32 @@
# -*- coding: utf-8 -*-
"""
jinja2.exceptions
~~~~~~~~~~~~~~~~~
Jinja exceptions.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
from jinja2._compat import imap, text_type, PY2, implements_to_string
from ._compat import imap
from ._compat import implements_to_string
from ._compat import PY2
from ._compat import text_type


class TemplateError(Exception):
"""Baseclass for all template errors."""

if PY2:

def __init__(self, message=None):
if message is not None:
message = text_type(message).encode('utf-8')
message = text_type(message).encode("utf-8")
Exception.__init__(self, message)

@property
def message(self):
if self.args:
message = self.args[0]
if message is not None:
return message.decode('utf-8', 'replace')
return message.decode("utf-8", "replace")

def __unicode__(self):
return self.message or u''
return self.message or u""

else:

def __init__(self, message=None):
Exception.__init__(self, message)

@@ -43,16 +40,28 @@ def message(self):

@implements_to_string
class TemplateNotFound(IOError, LookupError, TemplateError):
"""Raised if a template does not exist."""
"""Raised if a template does not exist.
.. versionchanged:: 2.11
If the given name is :class:`Undefined` and no message was
provided, an :exc:`UndefinedError` is raised.
"""

# looks weird, but removes the warning descriptor that just
# bogusly warns us about message being deprecated
message = None

def __init__(self, name, message=None):
IOError.__init__(self)
IOError.__init__(self, name)

if message is None:
from .runtime import Undefined

if isinstance(name, Undefined):
name._fail_with_undefined_error()

message = name

self.message = message
self.name = name
self.templates = [name]
@@ -66,13 +75,28 @@ class TemplatesNotFound(TemplateNotFound):
are selected. This is a subclass of :class:`TemplateNotFound`
exception, so just catching the base exception will catch both.
.. versionchanged:: 2.11
If a name in the list of names is :class:`Undefined`, a message
about it being undefined is shown rather than the empty string.
.. versionadded:: 2.2
"""

def __init__(self, names=(), message=None):
if message is None:
message = u'none of the templates given were found: ' + \
u', '.join(imap(text_type, names))
from .runtime import Undefined

parts = []

for name in names:
if isinstance(name, Undefined):
parts.append(name._undefined_message)
else:
parts.append(name)

message = u"none of the templates given were found: " + u", ".join(
imap(text_type, parts)
)
TemplateNotFound.__init__(self, names and names[-1] or None, message)
self.templates = list(names)

@@ -98,11 +122,11 @@ def __str__(self):
return self.message

# otherwise attach some stuff
location = 'line %d' % self.lineno
location = "line %d" % self.lineno
name = self.filename or self.name
if name:
location = 'File "%s", %s' % (name, location)
lines = [self.message, ' ' + location]
lines = [self.message, " " + location]

# if the source is set, add the line to the output
if self.source is not None:
@@ -111,9 +135,16 @@ def __str__(self):
except IndexError:
line = None
if line:
lines.append(' ' + line.strip())
lines.append(" " + line.strip())

return u"\n".join(lines)

return u'\n'.join(lines)
def __reduce__(self):
# https://bugs.python.org/issue1692335 Exceptions that take
# multiple required arguments have problems with pickling.
# Without this, raises TypeError: __init__() missing 1 required
# positional argument: 'lineno'
return self.__class__, (self.message, self.lineno, self.name, self.filename)


class TemplateAssertionError(TemplateSyntaxError):
387 changes: 232 additions & 155 deletions external/python/jinja2/ext.py

Large diffs are not rendered by default.

716 changes: 454 additions & 262 deletions external/python/jinja2/filters.py

Large diffs are not rendered by default.

58 changes: 31 additions & 27 deletions external/python/jinja2/idtracking.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from jinja2.visitor import NodeVisitor
from jinja2._compat import iteritems
from ._compat import iteritems
from .visitor import NodeVisitor


VAR_LOAD_PARAMETER = 'param'
VAR_LOAD_RESOLVE = 'resolve'
VAR_LOAD_ALIAS = 'alias'
VAR_LOAD_UNDEFINED = 'undefined'
VAR_LOAD_PARAMETER = "param"
VAR_LOAD_RESOLVE = "resolve"
VAR_LOAD_ALIAS = "alias"
VAR_LOAD_UNDEFINED = "undefined"


def find_symbols(nodes, parent_symbols=None):
@@ -23,7 +22,6 @@ def symbols_for_node(node, parent_symbols=None):


class Symbols(object):

def __init__(self, parent=None, level=None):
if level is None:
if parent is None:
@@ -41,7 +39,7 @@ def analyze_node(self, node, **kwargs):
visitor.visit(node, **kwargs)

def _define_ref(self, name, load=None):
ident = 'l_%d_%s' % (self.level, name)
ident = "l_%d_%s" % (self.level, name)
self.refs[name] = ident
if load is not None:
self.loads[ident] = load
@@ -62,8 +60,10 @@ def find_ref(self, name):
def ref(self, name):
rv = self.find_ref(name)
if rv is None:
raise AssertionError('Tried to resolve a name to a reference that '
'was unknown to the frame (%r)' % name)
raise AssertionError(
"Tried to resolve a name to a reference that "
"was unknown to the frame (%r)" % name
)
return rv

def copy(self):
@@ -118,7 +118,7 @@ def branch_update(self, branch_symbols):
if branch_count == len(branch_symbols):
continue
target = self.find_ref(name)
assert target is not None, 'should not happen'
assert target is not None, "should not happen"

if self.parent is not None:
outer_target = self.parent.find_ref(name)
@@ -149,43 +149,46 @@ def dump_param_targets(self):


class RootVisitor(NodeVisitor):

def __init__(self, symbols):
self.sym_visitor = FrameSymbolVisitor(symbols)

def _simple_visit(self, node, **kwargs):
for child in node.iter_child_nodes():
self.sym_visitor.visit(child)

visit_Template = visit_Block = visit_Macro = visit_FilterBlock = \
visit_Scope = visit_If = visit_ScopedEvalContextModifier = \
_simple_visit
visit_Template = (
visit_Block
) = (
visit_Macro
) = (
visit_FilterBlock
) = visit_Scope = visit_If = visit_ScopedEvalContextModifier = _simple_visit

def visit_AssignBlock(self, node, **kwargs):
for child in node.body:
self.sym_visitor.visit(child)

def visit_CallBlock(self, node, **kwargs):
for child in node.iter_child_nodes(exclude=('call',)):
for child in node.iter_child_nodes(exclude=("call",)):
self.sym_visitor.visit(child)

def visit_OverlayScope(self, node, **kwargs):
for child in node.body:
self.sym_visitor.visit(child)

def visit_For(self, node, for_branch='body', **kwargs):
if for_branch == 'body':
def visit_For(self, node, for_branch="body", **kwargs):
if for_branch == "body":
self.sym_visitor.visit(node.target, store_as_param=True)
branch = node.body
elif for_branch == 'else':
elif for_branch == "else":
branch = node.else_
elif for_branch == 'test':
elif for_branch == "test":
self.sym_visitor.visit(node.target, store_as_param=True)
if node.test is not None:
self.sym_visitor.visit(node.test)
return
else:
raise RuntimeError('Unknown for branch')
raise RuntimeError("Unknown for branch")
for item in branch or ():
self.sym_visitor.visit(item)

@@ -196,8 +199,9 @@ def visit_With(self, node, **kwargs):
self.sym_visitor.visit(child)

def generic_visit(self, node, *args, **kwargs):
raise NotImplementedError('Cannot find symbols for %r' %
node.__class__.__name__)
raise NotImplementedError(
"Cannot find symbols for %r" % node.__class__.__name__
)


class FrameSymbolVisitor(NodeVisitor):
@@ -208,11 +212,11 @@ def __init__(self, symbols):

def visit_Name(self, node, store_as_param=False, **kwargs):
"""All assignments to names go through this function."""
if store_as_param or node.ctx == 'param':
if store_as_param or node.ctx == "param":
self.symbols.declare_parameter(node.name)
elif node.ctx == 'store':
elif node.ctx == "store":
self.symbols.store(node.name)
elif node.ctx == 'load':
elif node.ctx == "load":
self.symbols.load(node.name)

def visit_NSRef(self, node, **kwargs):
775 changes: 442 additions & 333 deletions external/python/jinja2/lexer.py

Large diffs are not rendered by default.

135 changes: 79 additions & 56 deletions external/python/jinja2/loaders.py
Original file line number Diff line number Diff line change
@@ -1,35 +1,36 @@
# -*- coding: utf-8 -*-
"""
jinja2.loaders
~~~~~~~~~~~~~~
Jinja loader classes.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""API and implementations for loading templates from different data
sources.
"""
import os
import sys
import weakref
from types import ModuleType
from os import path
from hashlib import sha1
from jinja2.exceptions import TemplateNotFound
from jinja2.utils import open_if_exists, internalcode
from jinja2._compat import string_types, iteritems
from os import path
from types import ModuleType

from ._compat import abc
from ._compat import fspath
from ._compat import iteritems
from ._compat import string_types
from .exceptions import TemplateNotFound
from .utils import internalcode
from .utils import open_if_exists


def split_template_path(template):
"""Split a path into segments and perform a sanity check. If it detects
'..' in the path it will raise a `TemplateNotFound` error.
"""
pieces = []
for piece in template.split('/'):
if path.sep in piece \
or (path.altsep and path.altsep in piece) or \
piece == path.pardir:
for piece in template.split("/"):
if (
path.sep in piece
or (path.altsep and path.altsep in piece)
or piece == path.pardir
):
raise TemplateNotFound(template)
elif piece and piece != '.':
elif piece and piece != ".":
pieces.append(piece)
return pieces

@@ -86,15 +87,16 @@ def get_source(self, environment, template):
the template will be reloaded.
"""
if not self.has_source_access:
raise RuntimeError('%s cannot provide access to the source' %
self.__class__.__name__)
raise RuntimeError(
"%s cannot provide access to the source" % self.__class__.__name__
)
raise TemplateNotFound(template)

def list_templates(self):
"""Iterates over all templates. If the loader does not support that
it should raise a :exc:`TypeError` which is the default behavior.
"""
raise TypeError('this loader cannot iterate over all templates')
raise TypeError("this loader cannot iterate over all templates")

@internalcode
def load(self, environment, name, globals=None):
@@ -131,8 +133,9 @@ def load(self, environment, name, globals=None):
bucket.code = code
bcc.set_bucket(bucket)

return environment.template_class.from_code(environment, code,
globals, uptodate)
return environment.template_class.from_code(
environment, code, globals, uptodate
)


class FileSystemLoader(BaseLoader):
@@ -153,14 +156,20 @@ class FileSystemLoader(BaseLoader):
>>> loader = FileSystemLoader('/path/to/templates', followlinks=True)
.. versionchanged:: 2.8+
The *followlinks* parameter was added.
.. versionchanged:: 2.8
The ``followlinks`` parameter was added.
"""

def __init__(self, searchpath, encoding='utf-8', followlinks=False):
if isinstance(searchpath, string_types):
def __init__(self, searchpath, encoding="utf-8", followlinks=False):
if not isinstance(searchpath, abc.Iterable) or isinstance(
searchpath, string_types
):
searchpath = [searchpath]
self.searchpath = list(searchpath)

# In Python 3.5, os.path.join doesn't support Path. This can be
# simplified to list(searchpath) when Python 3.5 is dropped.
self.searchpath = [fspath(p) for p in searchpath]

self.encoding = encoding
self.followlinks = followlinks

@@ -183,19 +192,22 @@ def uptodate():
return path.getmtime(filename) == mtime
except OSError:
return False

return contents, filename, uptodate
raise TemplateNotFound(template)

def list_templates(self):
found = set()
for searchpath in self.searchpath:
walk_dir = os.walk(searchpath, followlinks=self.followlinks)
for dirpath, dirnames, filenames in walk_dir:
for dirpath, _, filenames in walk_dir:
for filename in filenames:
template = os.path.join(dirpath, filename) \
[len(searchpath):].strip(os.path.sep) \
.replace(os.path.sep, '/')
if template[:2] == './':
template = (
os.path.join(dirpath, filename)[len(searchpath) :]
.strip(os.path.sep)
.replace(os.path.sep, "/")
)
if template[:2] == "./":
template = template[2:]
if template not in found:
found.add(template)
@@ -217,10 +229,11 @@ class PackageLoader(BaseLoader):
from the file system and not a zip file.
"""

def __init__(self, package_name, package_path='templates',
encoding='utf-8'):
from pkg_resources import DefaultProvider, ResourceManager, \
get_provider
def __init__(self, package_name, package_path="templates", encoding="utf-8"):
from pkg_resources import DefaultProvider
from pkg_resources import get_provider
from pkg_resources import ResourceManager

provider = get_provider(package_name)
self.encoding = encoding
self.manager = ResourceManager()
@@ -230,14 +243,17 @@ def __init__(self, package_name, package_path='templates',

def get_source(self, environment, template):
pieces = split_template_path(template)
p = '/'.join((self.package_path,) + tuple(pieces))
p = "/".join((self.package_path,) + tuple(pieces))

if not self.provider.has_resource(p):
raise TemplateNotFound(template)

filename = uptodate = None

if self.filesystem_bound:
filename = self.provider.get_resource_filename(self.manager, p)
mtime = path.getmtime(filename)

def uptodate():
try:
return path.getmtime(filename) == mtime
@@ -249,19 +265,24 @@ def uptodate():

def list_templates(self):
path = self.package_path
if path[:2] == './':

if path[:2] == "./":
path = path[2:]
elif path == '.':
path = ''
elif path == ".":
path = ""

offset = len(path)
results = []

def _walk(path):
for filename in self.provider.resource_listdir(path):
fullname = path + '/' + filename
fullname = path + "/" + filename

if self.provider.resource_isdir(fullname):
_walk(fullname)
else:
results.append(fullname[offset:].lstrip('/'))
results.append(fullname[offset:].lstrip("/"))

_walk(path)
results.sort()
return results
@@ -334,7 +355,7 @@ class PrefixLoader(BaseLoader):
by loading ``'app2/index.html'`` the file from the second.
"""

def __init__(self, mapping, delimiter='/'):
def __init__(self, mapping, delimiter="/"):
self.mapping = mapping
self.delimiter = delimiter

@@ -434,19 +455,20 @@ class ModuleLoader(BaseLoader):
has_source_access = False

def __init__(self, path):
package_name = '_jinja2_module_templates_%x' % id(self)
package_name = "_jinja2_module_templates_%x" % id(self)

# create a fake module that looks for the templates in the
# path given.
mod = _TemplateModule(package_name)
if isinstance(path, string_types):

if not isinstance(path, abc.Iterable) or isinstance(path, string_types):
path = [path]
else:
path = list(path)
mod.__path__ = path

sys.modules[package_name] = weakref.proxy(mod,
lambda x: sys.modules.pop(package_name, None))
mod.__path__ = [fspath(p) for p in path]

sys.modules[package_name] = weakref.proxy(
mod, lambda x: sys.modules.pop(package_name, None)
)

# the only strong reference, the sys.modules entry is weak
# so that the garbage collector can remove it once the
@@ -456,20 +478,20 @@ def __init__(self, path):

@staticmethod
def get_template_key(name):
return 'tmpl_' + sha1(name.encode('utf-8')).hexdigest()
return "tmpl_" + sha1(name.encode("utf-8")).hexdigest()

@staticmethod
def get_module_filename(name):
return ModuleLoader.get_template_key(name) + '.py'
return ModuleLoader.get_template_key(name) + ".py"

@internalcode
def load(self, environment, name, globals=None):
key = self.get_template_key(name)
module = '%s.%s' % (self.package_name, key)
module = "%s.%s" % (self.package_name, key)
mod = getattr(self.module, module, None)
if mod is None:
try:
mod = __import__(module, None, None, ['root'])
mod = __import__(module, None, None, ["root"])
except ImportError:
raise TemplateNotFound(name)

@@ -478,4 +500,5 @@ def load(self, environment, name, globals=None):
sys.modules.pop(module, None)

return environment.template_class.from_module_dict(
environment, mod.__dict__, globals)
environment, mod.__dict__, globals
)
33 changes: 14 additions & 19 deletions external/python/jinja2/meta.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,18 @@
# -*- coding: utf-8 -*-
"""Functions that expose information about templates that might be
interesting for introspection.
"""
jinja2.meta
~~~~~~~~~~~
This module implements various functions that exposes information about
templates that might be interesting for various kinds of applications.
:copyright: (c) 2017 by the Jinja Team, see AUTHORS for more details.
:license: BSD, see LICENSE for more details.
"""
from jinja2 import nodes
from jinja2.compiler import CodeGenerator
from jinja2._compat import string_types, iteritems
from . import nodes
from ._compat import iteritems
from ._compat import string_types
from .compiler import CodeGenerator


class TrackingCodeGenerator(CodeGenerator):
"""We abuse the code generator for introspection."""

def __init__(self, environment):
CodeGenerator.__init__(self, environment, '<introspection>',
'<introspection>')
CodeGenerator.__init__(self, environment, "<introspection>", "<introspection>")
self.undeclared_identifiers = set()

def write(self, x):
@@ -29,7 +22,7 @@ def enter_frame(self, frame):
"""Remember all undeclared identifiers."""
CodeGenerator.enter_frame(self, frame)
for _, (action, param) in iteritems(frame.symbols.loads):
if action == 'resolve':
if action == "resolve" and param not in self.environment.globals:
self.undeclared_identifiers.add(param)


@@ -72,8 +65,9 @@ def find_referenced_templates(ast):
This function is useful for dependency tracking. For example if you want
to rebuild parts of the website after a layout template has changed.
"""
for node in ast.find_all((nodes.Extends, nodes.FromImport, nodes.Import,
nodes.Include)):
for node in ast.find_all(
(nodes.Extends, nodes.FromImport, nodes.Import, nodes.Include)
):
if not isinstance(node.template, nodes.Const):
# a tuple with some non consts in there
if isinstance(node.template, (nodes.Tuple, nodes.List)):
@@ -96,8 +90,9 @@ def find_referenced_templates(ast):
# a tuple or list (latter *should* not happen) made of consts,
# yield the consts that are strings. We could warn here for
# non string values
elif isinstance(node, nodes.Include) and \
isinstance(node.template.value, (tuple, list)):
elif isinstance(node, nodes.Include) and isinstance(
node.template.value, (tuple, list)
):
for template_name in node.template.value:
if isinstance(template_name, string_types):
yield template_name
248 changes: 61 additions & 187 deletions external/python/jinja2/nativetypes.py
Original file line number Diff line number Diff line change
@@ -1,220 +1,94 @@
import sys
from ast import literal_eval
from itertools import islice, chain
from jinja2 import nodes
from jinja2._compat import text_type
from jinja2.compiler import CodeGenerator, has_safe_repr
from jinja2.environment import Environment, Template
from jinja2.utils import concat, escape
from itertools import chain
from itertools import islice

from . import nodes
from ._compat import text_type
from .compiler import CodeGenerator
from .compiler import has_safe_repr
from .environment import Environment
from .environment import Template


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
:func:`ast.literal_eval`, the parsed value is returned. Otherwise, the
string is returned.
"""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
:func:`ast.literal_eval`, the parsed value is returned. Otherwise,
the string is returned.
:param nodes: Iterable of nodes to concatenate.
"""
head = list(islice(nodes, 2))

if not head:
return None

if len(head) == 1:
out = head[0]
raw = head[0]
else:
out = u''.join([text_type(v) for v in chain(head, nodes)])
raw = u"".join([text_type(v) for v in chain(head, nodes)])

try:
return literal_eval(out)
return literal_eval(raw)
except (ValueError, SyntaxError, MemoryError):
return out
return raw


class NativeCodeGenerator(CodeGenerator):
"""A code generator which avoids injecting ``to_string()`` calls around the
internal code Jinja uses to render templates.
"""A code generator which renders Python types by not adding
``to_string()`` around output nodes.
"""

def visit_Output(self, node, frame):
"""Same as :meth:`CodeGenerator.visit_Output`, but do not call
``to_string`` on output nodes in generated code.
"""
if self.has_known_extends and frame.require_output_check:
return

finalize = self.environment.finalize
finalize_context = getattr(finalize, 'contextfunction', False)
finalize_eval = getattr(finalize, 'evalcontextfunction', False)
finalize_env = getattr(finalize, 'environmentfunction', False)

if finalize is not None:
if finalize_context or finalize_eval:
const_finalize = None
elif finalize_env:
def const_finalize(x):
return finalize(self.environment, x)
else:
const_finalize = finalize
else:
def const_finalize(x):
return x

# If we are inside a frame that requires output checking, we do so.
outdent_later = False

if frame.require_output_check:
self.writeline('if parent_template is None:')
self.indent()
outdent_later = True

# Try to evaluate as many chunks as possible into a static string at
# compile time.
body = []

for child in node.nodes:
try:
if const_finalize is None:
raise nodes.Impossible()

const = child.as_const(frame.eval_ctx)
if not has_safe_repr(const):
raise nodes.Impossible()
except nodes.Impossible:
body.append(child)
continue

# the frame can't be volatile here, because otherwise the as_const
# function would raise an Impossible exception at that point
try:
if frame.eval_ctx.autoescape:
if hasattr(const, '__html__'):
const = const.__html__()
else:
const = escape(const)

const = const_finalize(const)
except Exception:
# if something goes wrong here we evaluate the node at runtime
# for easier debugging
body.append(child)
continue

if body and isinstance(body[-1], list):
body[-1].append(const)
else:
body.append([const])

# if we have less than 3 nodes or a buffer we yield or extend/append
if len(body) < 3 or frame.buffer is not None:
if frame.buffer is not None:
# for one item we append, for more we extend
if len(body) == 1:
self.writeline('%s.append(' % frame.buffer)
else:
self.writeline('%s.extend((' % frame.buffer)

self.indent()

for item in body:
if isinstance(item, list):
val = repr(native_concat(item))

if frame.buffer is None:
self.writeline('yield ' + val)
else:
self.writeline(val + ',')
else:
if frame.buffer is None:
self.writeline('yield ', item)
else:
self.newline(item)

close = 0

if finalize is not None:
self.write('environment.finalize(')

if finalize_context:
self.write('context, ')

close += 1

self.visit(item, frame)

if close > 0:
self.write(')' * close)

if frame.buffer is not None:
self.write(',')

if frame.buffer is not None:
# close the open parentheses
self.outdent()
self.writeline(len(body) == 1 and ')' or '))')

# otherwise we create a format string as this is faster in that case
else:
format = []
arguments = []

for item in body:
if isinstance(item, list):
format.append(native_concat(item).replace('%', '%%'))
else:
format.append('%s')
arguments.append(item)

self.writeline('yield ')
self.write(repr(concat(format)) + ' % (')
self.indent()

for argument in arguments:
self.newline(argument)
close = 0

if finalize is not None:
self.write('environment.finalize(')

if finalize_context:
self.write('context, ')
elif finalize_eval:
self.write('context.eval_ctx, ')
elif finalize_env:
self.write('environment, ')

close += 1

self.visit(argument, frame)
self.write(')' * close + ', ')

self.outdent()
self.writeline(')')
@staticmethod
def _default_finalize(value):
return value

def _output_const_repr(self, 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)

if not has_safe_repr(const):
raise nodes.Impossible()

if outdent_later:
self.outdent()
if isinstance(node, nodes.TemplateData):
return const

return finalize.const(const)

def _output_child_pre(self, node, frame, finalize):
if finalize.src is not None:
self.write(finalize.src)

def _output_child_post(self, node, frame, finalize):
if finalize.src is not None:
self.write(")")


class NativeEnvironment(Environment):
"""An environment that renders templates to native Python types."""

code_generator_class = NativeCodeGenerator


class NativeTemplate(Template):
environment_class = NativeEnvironment

def render(self, *args, **kwargs):
"""Render the template to produce a native Python type. 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
:func:`ast.literal_eval`, the parsed value is returned. Otherwise, the
string is returned.
"""Render the template to produce a native Python type. 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 :func:`ast.literal_eval`, the parsed value is returned.
Otherwise, the string is returned.
"""
vars = dict(*args, **kwargs)

try:
return native_concat(self.root_render_func(self.new_context(vars)))
except Exception:
exc_info = sys.exc_info()
return self.environment.handle_exception()

return self.environment.handle_exception(exc_info, True)


class NativeEnvironment(Environment):
"""An environment that renders templates to native Python types."""

code_generator_class = NativeCodeGenerator
template_class = NativeTemplate
NativeEnvironment.template_class = NativeTemplate
427 changes: 258 additions & 169 deletions external/python/jinja2/nodes.py

Large diffs are not rendered by default.

60 changes: 26 additions & 34 deletions external/python/jinja2/optimizer.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,15 @@
# -*- coding: utf-8 -*-
"""The optimizer tries to constant fold expressions and modify the AST
in place so that it should be faster to evaluate.
Because the AST does not contain all the scoping information and the
compiler has to find that out, we cannot do all the optimizations we
want. For example, loop unrolling doesn't work because unrolled loops
would have a different scope. The solution would be a second syntax tree
that stored the scoping rules.
"""
jinja2.optimizer
~~~~~~~~~~~~~~~~
The jinja optimizer is currently trying to constant fold a few expressions
and modify the AST in place so that it should be easier to evaluate it.
Because the AST does not contain all the scoping information and the
compiler has to find that out, we cannot do all the optimizations we
want. For example loop unrolling doesn't work because unrolled loops would
have a different scoping.
The solution would be a second syntax tree that has the scoping rules stored.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD.
"""
from jinja2 import nodes
from jinja2.visitor import NodeTransformer
from . import nodes
from .visitor import NodeTransformer


def optimize(node, environment):
@@ -28,22 +20,22 @@ def optimize(node, environment):


class Optimizer(NodeTransformer):

def __init__(self, environment):
self.environment = environment

def fold(self, node, eval_ctx=None):
"""Do constant folding."""
node = self.generic_visit(node)
try:
return nodes.Const.from_untrusted(node.as_const(eval_ctx),
lineno=node.lineno,
environment=self.environment)
except nodes.Impossible:
return node

visit_Add = visit_Sub = visit_Mul = visit_Div = visit_FloorDiv = \
visit_Pow = visit_Mod = visit_And = visit_Or = visit_Pos = visit_Neg = \
visit_Not = visit_Compare = visit_Getitem = visit_Getattr = visit_Call = \
visit_Filter = visit_Test = visit_CondExpr = fold
del fold
def generic_visit(self, node, *args, **kwargs):
node = super(Optimizer, self).generic_visit(node, *args, **kwargs)

# Do constant folding. Some other nodes besides Expr have
# as_const, but folding them causes errors later on.
if isinstance(node, nodes.Expr):
try:
return nodes.Const.from_untrusted(
node.as_const(args[0] if args else None),
lineno=node.lineno,
environment=self.environment,
)
except nodes.Impossible:
pass

return node
568 changes: 302 additions & 266 deletions external/python/jinja2/parser.py

Large diffs are not rendered by default.

693 changes: 448 additions & 245 deletions external/python/jinja2/runtime.py

Large diffs are not rendered by default.

198 changes: 110 additions & 88 deletions external/python/jinja2/sandbox.py
Original file line number Diff line number Diff line change
@@ -1,70 +1,66 @@
# -*- coding: utf-8 -*-
"""A sandbox layer that ensures unsafe operations cannot be performed.
Useful when the template itself comes from an untrusted source.
"""
jinja2.sandbox
~~~~~~~~~~~~~~
Adds a sandbox layer to Jinja as it was the default behavior in the old
Jinja 1 releases. This sandbox is slightly different from Jinja 1 as the
default behavior is easier to use.
The behavior can be changed by subclassing the environment.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD.
"""
import types
import operator
from jinja2.environment import Environment
from jinja2.exceptions import SecurityError
from jinja2._compat import string_types, PY2, abc, range_type
from jinja2.utils import Markup
import types
import warnings
from collections import deque
from string import Formatter

from markupsafe import EscapeFormatter
from string import Formatter
from markupsafe import Markup

from ._compat import abc
from ._compat import PY2
from ._compat import range_type
from ._compat import string_types
from .environment import Environment
from .exceptions import SecurityError

#: maximum number of items a range may produce
MAX_RANGE = 100000

#: attributes of function objects that are considered unsafe.
if PY2:
UNSAFE_FUNCTION_ATTRIBUTES = set(['func_closure', 'func_code', 'func_dict',
'func_defaults', 'func_globals'])
UNSAFE_FUNCTION_ATTRIBUTES = {
"func_closure",
"func_code",
"func_dict",
"func_defaults",
"func_globals",
}
else:
# On versions > python 2 the special attributes on functions are gone,
# but they remain on methods and generators for whatever reason.
UNSAFE_FUNCTION_ATTRIBUTES = set()


#: unsafe method attributes. function attributes are unsafe for methods too
UNSAFE_METHOD_ATTRIBUTES = set(['im_class', 'im_func', 'im_self'])
UNSAFE_METHOD_ATTRIBUTES = {"im_class", "im_func", "im_self"}

#: unsafe generator attirbutes.
UNSAFE_GENERATOR_ATTRIBUTES = set(['gi_frame', 'gi_code'])
#: unsafe generator attributes.
UNSAFE_GENERATOR_ATTRIBUTES = {"gi_frame", "gi_code"}

#: unsafe attributes on coroutines
UNSAFE_COROUTINE_ATTRIBUTES = set(['cr_frame', 'cr_code'])
UNSAFE_COROUTINE_ATTRIBUTES = {"cr_frame", "cr_code"}

#: unsafe attributes on async generators
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = set(['ag_code', 'ag_frame'])

import warnings
UNSAFE_ASYNC_GENERATOR_ATTRIBUTES = {"ag_code", "ag_frame"}

# make sure we don't warn in python 2.6 about stuff we don't care about
warnings.filterwarnings('ignore', 'the sets module', DeprecationWarning,
module='jinja2.sandbox')

from collections import deque
warnings.filterwarnings(
"ignore", "the sets module", DeprecationWarning, module=__name__
)

_mutable_set_types = (set,)
_mutable_mapping_types = (dict,)
_mutable_sequence_types = (list,)


# on python 2.x we can register the user collection types
try:
from UserDict import UserDict, DictMixin
from UserList import UserList

_mutable_mapping_types += (UserDict, DictMixin)
_mutable_set_types += (UserList,)
except ImportError:
@@ -73,6 +69,7 @@
# if sets is still available, register the mutable set from there as well
try:
from sets import Set

_mutable_set_types += (Set,)
except ImportError:
pass
@@ -82,22 +79,46 @@
_mutable_mapping_types += (abc.MutableMapping,)
_mutable_sequence_types += (abc.MutableSequence,)


_mutable_spec = (
(_mutable_set_types, frozenset([
'add', 'clear', 'difference_update', 'discard', 'pop', 'remove',
'symmetric_difference_update', 'update'
])),
(_mutable_mapping_types, frozenset([
'clear', 'pop', 'popitem', 'setdefault', 'update'
])),
(_mutable_sequence_types, frozenset([
'append', 'reverse', 'insert', 'sort', 'extend', 'remove'
])),
(deque, frozenset([
'append', 'appendleft', 'clear', 'extend', 'extendleft', 'pop',
'popleft', 'remove', 'rotate'
]))
(
_mutable_set_types,
frozenset(
[
"add",
"clear",
"difference_update",
"discard",
"pop",
"remove",
"symmetric_difference_update",
"update",
]
),
),
(
_mutable_mapping_types,
frozenset(["clear", "pop", "popitem", "setdefault", "update"]),
),
(
_mutable_sequence_types,
frozenset(["append", "reverse", "insert", "sort", "extend", "remove"]),
),
(
deque,
frozenset(
[
"append",
"appendleft",
"clear",
"extend",
"extendleft",
"pop",
"popleft",
"remove",
"rotate",
]
),
),
)


@@ -115,7 +136,7 @@ def __init__(self, args, kwargs):
self._last_index = 0

def __getitem__(self, key):
if key == '':
if key == "":
idx = self._last_index
self._last_index += 1
try:
@@ -133,9 +154,9 @@ def __len__(self):


def inspect_format_method(callable):
if not isinstance(callable, (types.MethodType,
types.BuiltinMethodType)) or \
callable.__name__ not in ('format', 'format_map'):
if not isinstance(
callable, (types.MethodType, types.BuiltinMethodType)
) or callable.__name__ not in ("format", "format_map"):
return None
obj = callable.__self__
if isinstance(obj, string_types):
@@ -186,24 +207,25 @@ def is_internal_attribute(obj, attr):
if attr in UNSAFE_FUNCTION_ATTRIBUTES:
return True
elif isinstance(obj, types.MethodType):
if attr in UNSAFE_FUNCTION_ATTRIBUTES or \
attr in UNSAFE_METHOD_ATTRIBUTES:
if attr in UNSAFE_FUNCTION_ATTRIBUTES or attr in UNSAFE_METHOD_ATTRIBUTES:
return True
elif isinstance(obj, type):
if attr == 'mro':
if attr == "mro":
return True
elif isinstance(obj, (types.CodeType, types.TracebackType, types.FrameType)):
return True
elif isinstance(obj, types.GeneratorType):
if attr in UNSAFE_GENERATOR_ATTRIBUTES:
return True
elif hasattr(types, 'CoroutineType') and isinstance(obj, types.CoroutineType):
elif hasattr(types, "CoroutineType") and isinstance(obj, types.CoroutineType):
if attr in UNSAFE_COROUTINE_ATTRIBUTES:
return True
elif hasattr(types, 'AsyncGeneratorType') and isinstance(obj, types.AsyncGeneratorType):
elif hasattr(types, "AsyncGeneratorType") and isinstance(
obj, types.AsyncGeneratorType
):
if attr in UNSAFE_ASYNC_GENERATOR_ATTRIBUTES:
return True
return attr.startswith('__')
return attr.startswith("__")


def modifies_known_mutable(obj, attr):
@@ -244,28 +266,26 @@ class SandboxedEnvironment(Environment):
raised. However also other exceptions may occur during the rendering so
the caller has to ensure that all exceptions are caught.
"""

sandboxed = True

#: default callback table for the binary operators. A copy of this is
#: available on each instance of a sandboxed environment as
#: :attr:`binop_table`
default_binop_table = {
'+': operator.add,
'-': operator.sub,
'*': operator.mul,
'/': operator.truediv,
'//': operator.floordiv,
'**': operator.pow,
'%': operator.mod
"+": operator.add,
"-": operator.sub,
"*": operator.mul,
"/": operator.truediv,
"//": operator.floordiv,
"**": operator.pow,
"%": operator.mod,
}

#: default callback table for the unary operators. A copy of this is
#: available on each instance of a sandboxed environment as
#: :attr:`unop_table`
default_unop_table = {
'+': operator.pos,
'-': operator.neg
}
default_unop_table = {"+": operator.pos, "-": operator.neg}

#: a set of binary operators that should be intercepted. Each operator
#: that is added to this set (empty by default) is delegated to the
@@ -301,7 +321,7 @@ class SandboxedEnvironment(Environment):
def intercept_unop(self, operator):
"""Called during template compilation with the name of a unary
operator to check if it should be intercepted at runtime. If this
method returns `True`, :meth:`call_unop` is excuted for this unary
method returns `True`, :meth:`call_unop` is executed for this unary
operator. The default implementation of :meth:`call_unop` will use
the :attr:`unop_table` dictionary to perform the operator with the
same logic as the builtin one.
@@ -315,10 +335,9 @@ def intercept_unop(self, operator):
"""
return False


def __init__(self, *args, **kwargs):
Environment.__init__(self, *args, **kwargs)
self.globals['range'] = safe_range
self.globals["range"] = safe_range
self.binop_table = self.default_binop_table.copy()
self.unop_table = self.default_unop_table.copy()

@@ -329,16 +348,17 @@ def is_safe_attribute(self, obj, attr, value):
special attributes of internal python objects as returned by the
:func:`is_internal_attribute` function.
"""
return not (attr.startswith('_') or is_internal_attribute(obj, attr))
return not (attr.startswith("_") or is_internal_attribute(obj, attr))

def is_safe_callable(self, obj):
"""Check if an object is safely callable. Per default a function is
considered safe unless the `unsafe_callable` attribute exists and is
True. Override this method to alter the behavior, but this won't
affect the `unsafe` decorator from this module.
"""
return not (getattr(obj, 'unsafe_callable', False) or
getattr(obj, 'alters_data', False))
return not (
getattr(obj, "unsafe_callable", False) or getattr(obj, "alters_data", False)
)

def call_binop(self, context, operator, left, right):
"""For intercepted binary operator calls (:meth:`intercepted_binops`)
@@ -398,11 +418,13 @@ def getattr(self, obj, attribute):

def unsafe_undefined(self, obj, attribute):
"""Return an undefined object for unsafe attributes."""
return self.undefined('access to attribute %r of %r '
'object is unsafe.' % (
attribute,
obj.__class__.__name__
), name=attribute, obj=obj, exc=SecurityError)
return self.undefined(
"access to attribute %r of %r "
"object is unsafe." % (attribute, obj.__class__.__name__),
name=attribute,
obj=obj,
exc=SecurityError,
)

def format_string(self, s, args, kwargs, format_func=None):
"""If a format call is detected, then this is routed through this
@@ -413,10 +435,10 @@ def format_string(self, s, args, kwargs, format_func=None):
else:
formatter = SandboxedFormatter(self)

if format_func is not None and format_func.__name__ == 'format_map':
if format_func is not None and format_func.__name__ == "format_map":
if len(args) != 1 or kwargs:
raise TypeError(
'format_map() takes exactly one argument %d given'
"format_map() takes exactly one argument %d given"
% (len(args) + (kwargs is not None))
)

@@ -427,7 +449,7 @@ def format_string(self, s, args, kwargs, format_func=None):
rv = formatter.vformat(s, args, kwargs)
return type(s)(rv)

def call(__self, __context, __obj, *args, **kwargs):
def call(__self, __context, __obj, *args, **kwargs): # noqa: B902
"""Call an object from sandboxed code."""
fmt = inspect_format_method(__obj)
if fmt is not None:
@@ -436,7 +458,7 @@ def call(__self, __context, __obj, *args, **kwargs):
# the double prefixes are to avoid double keyword argument
# errors when proxying the call.
if not __self.is_safe_callable(__obj):
raise SecurityError('%r is not safely callable' % (__obj,))
raise SecurityError("%r is not safely callable" % (__obj,))
return __context.call(__obj, *args, **kwargs)


@@ -452,16 +474,16 @@ def is_safe_attribute(self, obj, attr, value):
return not modifies_known_mutable(obj, attr)


# This really is not a public API apparenlty.
# 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

@@ -475,14 +497,14 @@ def get_field(self, field_name, args, kwargs):
obj = self._env.getitem(obj, i)
return obj, first

class SandboxedFormatter(SandboxedFormatterMixin, Formatter):

class SandboxedFormatter(SandboxedFormatterMixin, Formatter):
def __init__(self, env):
SandboxedFormatterMixin.__init__(self, env)
Formatter.__init__(self)

class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):

class SandboxedEscapeFormatter(SandboxedFormatterMixin, EscapeFormatter):
def __init__(self, env, escape):
SandboxedFormatterMixin.__init__(self, env)
EscapeFormatter.__init__(self, escape)
139 changes: 90 additions & 49 deletions external/python/jinja2/tests.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,17 @@
# -*- coding: utf-8 -*-
"""
jinja2.tests
~~~~~~~~~~~~
Jinja test functions. Used with the "is" operator.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD, see LICENSE for more details.
"""
"""Built-in template tests used with the ``is`` operator."""
import decimal
import operator
import re
from jinja2.runtime import Undefined
from jinja2._compat import text_type, string_types, integer_types, abc
import decimal

number_re = re.compile(r'^-?\d+(\.\d+)?$')
regex_type = type(number_re)

from ._compat import abc
from ._compat import integer_types
from ._compat import string_types
from ._compat import text_type
from .runtime import Undefined

number_re = re.compile(r"^-?\d+(\.\d+)?$")
regex_type = type(number_re)
test_callable = callable


@@ -63,6 +57,48 @@ def test_none(value):
return value is None


def test_boolean(value):
"""Return true if the object is a boolean value.
.. versionadded:: 2.11
"""
return value is True or value is False


def test_false(value):
"""Return true if the object is False.
.. versionadded:: 2.11
"""
return value is False


def test_true(value):
"""Return true if the object is True.
.. versionadded:: 2.11
"""
return value is True


# NOTE: The existing 'number' test matches booleans and floats
def test_integer(value):
"""Return true if the object is an integer.
.. versionadded:: 2.11
"""
return isinstance(value, integer_types) and value is not True and value is not False


# NOTE: The existing 'number' test matches booleans and integers
def test_float(value):
"""Return true if the object is a float.
.. versionadded:: 2.11
"""
return isinstance(value, float)


def test_lower(value):
"""Return true if the variable is lowercased."""
return text_type(value).islower()
@@ -98,7 +134,7 @@ def test_sequence(value):
try:
len(value)
value.__getitem__
except:
except Exception:
return False
return True

@@ -127,7 +163,7 @@ def test_iterable(value):

def test_escaped(value):
"""Check if the value is escaped."""
return hasattr(value, '__html__')
return hasattr(value, "__html__")


def test_in(value, seq):
@@ -139,36 +175,41 @@ def test_in(value, seq):


TESTS = {
'odd': test_odd,
'even': test_even,
'divisibleby': test_divisibleby,
'defined': test_defined,
'undefined': test_undefined,
'none': test_none,
'lower': test_lower,
'upper': test_upper,
'string': test_string,
'mapping': test_mapping,
'number': test_number,
'sequence': test_sequence,
'iterable': test_iterable,
'callable': test_callable,
'sameas': test_sameas,
'escaped': test_escaped,
'in': test_in,
'==': operator.eq,
'eq': operator.eq,
'equalto': operator.eq,
'!=': operator.ne,
'ne': operator.ne,
'>': operator.gt,
'gt': operator.gt,
'greaterthan': operator.gt,
'ge': operator.ge,
'>=': operator.ge,
'<': operator.lt,
'lt': operator.lt,
'lessthan': operator.lt,
'<=': operator.le,
'le': operator.le,
"odd": test_odd,
"even": test_even,
"divisibleby": test_divisibleby,
"defined": test_defined,
"undefined": test_undefined,
"none": test_none,
"boolean": test_boolean,
"false": test_false,
"true": test_true,
"integer": test_integer,
"float": test_float,
"lower": test_lower,
"upper": test_upper,
"string": test_string,
"mapping": test_mapping,
"number": test_number,
"sequence": test_sequence,
"iterable": test_iterable,
"callable": test_callable,
"sameas": test_sameas,
"escaped": test_escaped,
"in": test_in,
"==": operator.eq,
"eq": operator.eq,
"equalto": operator.eq,
"!=": operator.ne,
"ne": operator.ne,
">": operator.gt,
"gt": operator.gt,
"greaterthan": operator.gt,
"ge": operator.ge,
">=": operator.ge,
"<": operator.lt,
"lt": operator.lt,
"lessthan": operator.lt,
"<=": operator.le,
"le": operator.le,
}
399 changes: 247 additions & 152 deletions external/python/jinja2/utils.py

Large diffs are not rendered by default.

14 changes: 4 additions & 10 deletions external/python/jinja2/visitor.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
# -*- coding: utf-8 -*-
"""API for traversing the AST nodes. Implemented by the compiler and
meta introspection.
"""
jinja2.visitor
~~~~~~~~~~~~~~
This module implements a visitor for the nodes.
:copyright: (c) 2017 by the Jinja Team.
:license: BSD.
"""
from jinja2.nodes import Node
from .nodes import Node


class NodeVisitor(object):
@@ -28,7 +22,7 @@ def get_visitor(self, node):
exists for this node. In that case the generic visit function is
used instead.
"""
method = 'visit_' + node.__class__.__name__
method = "visit_" + node.__class__.__name__
return getattr(self, method, None)

def visit(self, node, *args, **kwargs):
10 changes: 5 additions & 5 deletions maintainer-scripts/common.sh
Original file line number Diff line number Diff line change
@@ -36,7 +36,7 @@ makeSubset() {

COMMON_FILES=".gitignore .gitattributes .git-blame-ignore-revs CODE_OF_CONDUCT.md LICENSES .reuse .editorconfig HOTFIX"
export COMMON_FILES
COMMON_EXCLUDE_PATTERN="KhronosExperimental"
COMMON_EXCLUDE_PATTERN="(KhronosExperimental|KhronosConfidential)"
export COMMON_EXCLUDE_PATTERN

add_to_tar() {
@@ -129,7 +129,7 @@ getDocsFilenames() {
specification/sources/extprocess/ \
include/ \
specification/ \
| grep -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -E -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -v "specification/loader" \
| grep -v "vuid[.]adoc" \
| grep -v "CMakeLists.txt" \
@@ -212,7 +212,7 @@ getSDKSourceFilenames() {
src/tests \
src/version.cmake \
src/version.gradle \
| grep -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -E -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -v "conformance" \
| grep -v "template_gen_dispatch" \
| grep -v "function_info" \
@@ -251,7 +251,7 @@ getSDKFilenames() {
src/external/jsoncpp \
src/loader \
src/version.cmake \
| grep -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -E -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -v "gfxwrapper" \
| grep -v "include/.gitignore" \
| grep -v "images"
@@ -313,7 +313,7 @@ getConformanceFilenames() {
src/scripts \
src/version.cmake \
src/version.gradle \
| grep -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -E -v "${COMMON_EXCLUDE_PATTERN}" \
| grep -v "htmldiff" \
| grep -v "katex"
}
2 changes: 2 additions & 0 deletions maintainer-scripts/publish-aar/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -34,9 +34,11 @@ publishing {
create<MavenPublication>("maven") {

artifactId = "openxr_loader_for_android"

artifact(loaderAar) {
extension = "aar"
}

artifact(loaderSourcesJar) {
extension = "jar"
classifier = "sources"
2 changes: 1 addition & 1 deletion specification/Makefile
Original file line number Diff line number Diff line change
@@ -32,7 +32,7 @@ ifneq (,$(strip $(VERY_STRICT)))
ASCIIDOC := $(ASCIIDOC) --failure-level WARN
endif

SPECREVISION = 1.0.33
SPECREVISION = 1.0.34
REVISION_COMPONENTS = $(subst ., ,$(SPECREVISION))
MAJORMINORVER = $(word 1,$(REVISION_COMPONENTS)).$(word 2,$(REVISION_COMPONENTS))

13 changes: 12 additions & 1 deletion specification/loader/design.adoc
Original file line number Diff line number Diff line change
@@ -57,6 +57,7 @@ it requires a list of available runtime manifest files.
[source,c++]
----
static XrResult RuntimeManifestFile::FindManifestFiles(
const std::string &openxr_command,
std::vector<std::unique_ptr<RuntimeManifestFile>> &manifest_files);
----
* pname:manifest_files is a vector that will be used to store a unique_ptr
@@ -101,7 +102,7 @@ it requires a list of available API layer manifest files.
[source,c++]
----
static XrResult ApiLayerManifestFile::FindManifestFiles(
ManifestFileType type,
const std::string &openxr_command, ManifestFileType type,
std::vector<std::unique_ptr<ApiLayerManifestFile>> &manifest_files);
----
* pname:type indicates the specific type of manifest file being searched
@@ -826,6 +827,16 @@ It returns true if the environment variable is set.

Access to certain environment variables needs to be done in a way that
maintains operational security of the program.

[NOTE]
.Note
****
Specifically, the loader will not use environment variables which control
code loading for admin (high integrity) processes on Windows as
the environment variables can be set by non-admin (medium integrity)
processes.
****

To read a secure environment variable, the loader calls
fname:PlatformUtilsGetSecureEnv:

Loading

0 comments on commit 455583c

Please sign in to comment.